[PATCHv2] Revert "virtio_console: Initialize guest_connected=true for rproc_serial"
From: Sjur Brændeland This reverts commit 8078db789a92b10ff6e2d713231b5367e014c53b, and adds a lengthy comment explaining the problem area. The reverted patch caused opening of ports to fail for rproc_serial. In probe guest_connected was set to true, but port_fops_open() fails with -EMFILE if guest_connected already is true. Signed-off-by: Sjur Brændeland --- drivers/char/virtio_console.c | 22 -- 1 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e905d5f..e6ba6b7 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1436,7 +1436,7 @@ static int add_port(struct ports_device *portdev, u32 id) * rproc_serial does not want the console port, only * the generic port implementation. */ - port->host_connected = port->guest_connected = true; + port->host_connected = true; else if (!use_multiport(port->portdev)) { /* * If we're not using multiport support, @@ -1752,13 +1752,23 @@ static void in_intr(struct virtqueue *vq) port->inbuf = get_inbuf(port); /* -* Don't queue up data when port is closed. This condition +* Normally the port should not accept data when the port is +* closed. For generic serial ports, the host won't (shouldn't) +* send data till the guest is connected. But this condition * can be reached when a console port is not yet connected (no -* tty is spawned) and the host sends out data to console -* ports. For generic serial ports, the host won't -* (shouldn't) send data till the guest is connected. +* tty is spawned) and the other side sends out data over the +* vring, or when a remote devices start sending data before +* the ports are opened. +* +* A generic serial port will discard data if not connected, +* while console ports and rproc-serial ports accepts data at +* any time. rproc-serial is initiated with guest_connected to +* false because port_fops_open expects this. Console ports are +* hooked up with an HVC console and is initialized with +* guest_connected to true. */ - if (!port->guest_connected) + + if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev)) discard_port_data(port); spin_unlock_irqrestore(&port->inbuf_lock, flags); -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH] Revert "virtio_console: Initialize guest_connected=true for rproc_serial"
From: Sjur Brændeland This reverts commit 8078db789a92b10ff6e2d713231b5367e014c53b. The reverted patch caused opening of ports to fail for rproc_serial. In probe guest_connected was set to true, but port_fops_open() fails with -EMFILE if guest_connected already is true. Signed-off-by: Sjur Brændeland --- Hi Rusty, Here is a fix intended for 3.9. Sorry for the churn here :-( Regards, Sjur drivers/char/virtio_console.c |7 +-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e905d5f..031be0b 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1436,7 +1436,7 @@ static int add_port(struct ports_device *portdev, u32 id) * rproc_serial does not want the console port, only * the generic port implementation. */ - port->host_connected = port->guest_connected = true; + port->host_connected = true; else if (!use_multiport(port->portdev)) { /* * If we're not using multiport support, @@ -1757,8 +1757,11 @@ static void in_intr(struct virtqueue *vq) * tty is spawned) and the host sends out data to console * ports. For generic serial ports, the host won't * (shouldn't) send data till the guest is connected. +* However a remote device might send data before the port is +* connected. So don't remove data from a rproc_serial device. */ - if (!port->guest_connected) + + if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev)) discard_port_data(port); spin_unlock_irqrestore(&port->inbuf_lock, flags); -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCHv2] virtio: Introduce vringh wrappers in virtio_config
From: Sjur Brændeland Add wrappers for the host vrings to support loose coupling between the virtio device and driver. A new struct vringh_config_ops with the functions find_vrhs() and del_vrhs() is added to the virtio_device struct. This enables virtio drivers to manage virtio host rings without detailed knowledge of how the vrings are created and deleted. The function vringh_notify() is added so vringh clients can notify the other side that buffers are added to the used-ring. Cc: Ohad Ben-Cohen Cc: Rusty Russell Signed-off-by: Sjur Brændeland --- Hi Rusty, >It's weird that you conflate the host and guest ring sides in rpmsg, but >that might make sense if they're really bound together. Weird or not, CAIF-virtio is design to use guest rings for TX traffic, and host rings for RX traffic. The motivation for this design is to allow zero-copy in the data-path on the remote-device/modem. Changes since v1: - Moved find_vrhs() and del_vrhs() to a separate struct vringh_config_ops. - Moved definition of struct vringh_config_ops into vringh.h - Added vringh_config field to struct virtio_device - Removed priv pointer field from struct vringh There are a number of different ways to do this, let me know if you want this changed in any way. Thanks, Sjur include/linux/virtio.h |3 +++ include/linux/vringh.h | 29 + 2 files changed, 32 insertions(+), 0 deletions(-) diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 00ccc40..5b71fc1 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -8,6 +8,7 @@ #include #include #include +#include /** * virtqueue - a queue to register buffers for sending or receiving. @@ -70,6 +71,7 @@ static inline unsigned int virtqueue_get_queue_index(struct virtqueue *vq) * @dev: underlying device. * @id: the device type identification (used to match it with a driver). * @config: the configuration ops for this device. + * @vringh_config: configuration ops for host vrings. * @vqs: the list of virtqueues for this device. * @features: the features supported by both driver and device. * @priv: private pointer for the driver's use. @@ -79,6 +81,7 @@ struct virtio_device { struct device dev; struct virtio_device_id id; struct virtio_config_ops *config; + struct vringh_config_ops *vringh_config; struct list_head vqs; /* Note that this is a Linux set_bit-style bitmap. */ unsigned long features[1]; diff --git a/include/linux/vringh.h b/include/linux/vringh.h index ab41185..c7d9289 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -50,6 +50,28 @@ struct vringh { /* The vring (note: it may contain user pointers!) */ struct vring vring; + + /* The function to call to notify the guest about added buffers */ + void (*notify)(struct vringh *); +}; + +/** + * struct vringh_config_ops - ops for creating a host vring from a virtio driver + * @find_vrhs: find the host vrings and instantiate them + * vdev: the virtio_device + * nhvrs: the number of host vrings to find + * hvrs: on success, includes new host vrings + * callbacks: array of driver callbacks, for each host vring + * include a NULL entry for vqs that do not need a callback + * Returns 0 on success or error status + * @del_vrhs: free the host vrings found by find_vrhs(). + */ +struct virtio_device; +typedef void vrh_callback_t(struct virtio_device *, struct vringh *); +struct vringh_config_ops { + int (*find_vrhs)(struct virtio_device *vdev, unsigned nhvrs, +struct vringh *vrhs[], vrh_callback_t *callbacks[]); + void (*del_vrhs)(struct virtio_device *vdev); }; /* The memory the vring can access, and what offset to apply. */ @@ -182,4 +204,11 @@ void vringh_notify_disable_kern(struct vringh *vrh); int vringh_need_notify_kern(struct vringh *vrh); +/* Notify the guest about buffers added to the used ring */ +static inline void vringh_notify(struct vringh *vrh) +{ + if (vrh->notify) + vrh->notify(vrh); +} + #endif /* _LINUX_VRINGH_H */ -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH vringh] virtio: Introduce vringh wrappers in virtio_config
From: Sjur Brændeland Add wrappers for the host vrings to support loose coupling between the virtio device and driver. The functions find_vrhs() and del_vrhs() are added to struct virtio_config_ops to manage the host vrings. The function vringh_notify() is added so the guest can be kicked when buffers are added to the used-ring. This enables the virtio drivers to manage the virtio rings without knowledge of how the host vrings are managed. Cc: Ohad Ben-Cohen Signed-off-by: Sjur Brændeland --- include/linux/virtio_config.h | 13 + include/linux/vringh.h| 13 + 2 files changed, 26 insertions(+), 0 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 29b9104..88dd5ae 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -51,7 +51,17 @@ * This returns a pointer to the bus name a la pci_name from which * the caller can then copy. * @set_vq_affinity: set the affinity for a virtqueue. + * @find_vrhs: find the host vrings and instantiate them + * vdev: the virtio_device + * nhvrs: the number of host vrings to find + * hvrs: on success, includes new host vrings + * callbacks: array of driver callbacks, for each host vring + * include a NULL entry for vqs that do not need a callback + * Returns 0 on success or error status + * @del_vrhs: free the host vrings found by find_vrhs(). */ +struct vringh; +typedef void vrh_callback_t(struct virtio_device *, struct vringh *); typedef void vq_callback_t(struct virtqueue *); struct virtio_config_ops { void (*get)(struct virtio_device *vdev, unsigned offset, @@ -70,6 +80,9 @@ struct virtio_config_ops { void (*finalize_features)(struct virtio_device *vdev); const char *(*bus_name)(struct virtio_device *vdev); int (*set_vq_affinity)(struct virtqueue *vq, int cpu); + int (*find_vrhs)(struct virtio_device *vdev, unsigned nhvrs, +struct vringh *vrhs[], vrh_callback_t *callbacks[]); + void (*del_vrhs)(struct virtio_device *vdev); }; /* If driver didn't advertise the feature, it will never appear. */ diff --git a/include/linux/vringh.h b/include/linux/vringh.h index ab41185..8156f51 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -50,6 +50,12 @@ struct vringh { /* The vring (note: it may contain user pointers!) */ struct vring vring; + + /* The function to call when buffers are available */ + void (*notify)(struct vringh *); + + /* A pointer for the vringh clients to use. */ + void *priv; }; /* The memory the vring can access, and what offset to apply. */ @@ -182,4 +188,11 @@ void vringh_notify_disable_kern(struct vringh *vrh); int vringh_need_notify_kern(struct vringh *vrh); +/* Notify the guest about buffers added to the used ring */ +static inline void vringh_notify(struct vringh *vrh) +{ + if (vrh->notify) + vrh->notify(vrh); +} + #endif /* _LINUX_VRINGH_H */ -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH] virtio_console: Initialize guest_connected=true for rproc_serial
From: Sjur Brændeland When rproc_serial is initialized, guest_connected should be set to true. We can then revert the extra checks introduced in commit: "virtio_console: Let unconnected rproc device receive data." Signed-off-by: Sjur Brændeland --- drivers/char/virtio_console.c |7 ++- 1 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 2cfd5a0..5afc8f6 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1436,7 +1436,7 @@ static int add_port(struct ports_device *portdev, u32 id) * rproc_serial does not want the console port, only * the generic port implementation. */ - port->host_connected = true; + port->host_connected = port->guest_connected = true; else if (!use_multiport(port->portdev)) { /* * If we're not using multiport support, @@ -1757,11 +1757,8 @@ static void in_intr(struct virtqueue *vq) * tty is spawned) and the host sends out data to console * ports. For generic serial ports, the host won't * (shouldn't) send data till the guest is connected. -* However a remote device might send data before the port is -* connected. So don't remove data from a rproc_serial device. */ - - if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev)) + if (!port->guest_connected) discard_port_data(port); spin_unlock_irqrestore(&port->inbuf_lock, flags); -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCHv2 vringh 3/3] caif_virtio: Introduce caif over virtio
From: Vikram ARV Add the the Virtio shared memory driver for STE Modems. caif_virtio is implemented utilizing the virtio framework for data transport and is managed with the remoteproc frameworks. The Virtio queue is used for transmitting data to the modem, and the new vringh implementation is receiving data over the vring. Signed-off-by: Vikram ARV Signed-off-by: Sjur Brændeland cc: David S. Miller cc: Ohad Ben-Cohen cc: Rusty Russell cc: Ido Yariv cc: Erwan Yvin --- As mentioned earlier this patch-set will go via Rusty's git. Changes since V1: - update to new vringh API, - use module_virtio_driver macro - call tasklet_kill from cfv_remove(). Thanks, Sjur drivers/net/caif/Kconfig|8 + drivers/net/caif/Makefile |3 + drivers/net/caif/caif_virtio.c | 547 +++ include/linux/virtio_caif.h | 24 ++ include/uapi/linux/virtio_ids.h |1 + 5 files changed, 583 insertions(+), 0 deletions(-) create mode 100644 drivers/net/caif/caif_virtio.c create mode 100644 include/linux/virtio_caif.h diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig index abf4d7a..a8b67e9 100644 --- a/drivers/net/caif/Kconfig +++ b/drivers/net/caif/Kconfig @@ -47,3 +47,11 @@ config CAIF_HSI The caif low level driver for CAIF over HSI. Be aware that if you enable this then you also need to enable a low-level HSI driver. + +config CAIF_VIRTIO + tristate "CAIF virtio transport driver" + depends on CAIF + depends on REMOTEPROC + default n + ---help--- + The caif driver for CAIF over Virtio. diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile index 91dff86..d9ee26a 100644 --- a/drivers/net/caif/Makefile +++ b/drivers/net/caif/Makefile @@ -13,3 +13,6 @@ obj-$(CONFIG_CAIF_SHM) += caif_shm.o # HSI interface obj-$(CONFIG_CAIF_HSI) += caif_hsi.o + +# Virtio interface +obj-$(CONFIG_CAIF_VIRTIO) += caif_virtio.o diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c new file mode 100644 index 000..d4f339c --- /dev/null +++ b/drivers/net/caif/caif_virtio.c @@ -0,0 +1,547 @@ +/* + * Copyright (C) ST-Ericsson AB 2012 + * Contact: Sjur Brendeland / sjur.brandel...@stericsson.com + * Authors: Vicram Arv / vikram@stericsson.com, + * Dmitry Tarnyagin / dmitry.tarnya...@stericsson.com + * Sjur Brendeland / sjur.brandel...@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Vicram Arv "); +MODULE_AUTHOR("Sjur Brendeland vdev->priv; + tasklet_schedule(&cfv->tx_release_tasklet); +} + +/* This is invoked whenever the remote processor completed processing + * a TX msg we just sent it, and the buffer is put back to the used ring. + */ +static void cfv_release_used_buf(struct virtqueue *vq_tx) +{ + struct cfv_info *cfv = vq_tx->vdev->priv; + unsigned long flags; + + BUG_ON(vq_tx != cfv->vq_tx); + WARN_ON_ONCE(irqs_disabled()); + + for (;;) { + unsigned int len; + struct token_info *buf_info; + + /* Get used buffer from used ring to recycle used descriptors */ + spin_lock_irqsave(&cfv->tx_lock, flags); + buf_info = virtqueue_get_buf(vq_tx, &len); + + if (!buf_info) + goto out; + + BUG_ON(!cfv->queued_tx); + if (--cfv->queued_tx <= cfv->watermark_tx) { + cfv->watermark_tx = 0; + netif_tx_wake_all_queues(cfv->ndev); + } + spin_unlock_irqrestore(&cfv->tx_lock, flags); + + dma_free_coherent(vq_tx->vdev->dev.parent->parent, + buf_info->size, buf_info->vaddr, + buf_info->dma_handle); + kfree(buf_info); + } + return; +out: + spin_unlock_irqrestore(&cfv->tx_lock, flags); +} + +static struct sk_buff *cfv_alloc_and_copy_skb(int *err, + struct cfv_info *cfv, + u8 *frm, u32 frm_len) +{ + struct sk_buff *skb; + u32 cfpkt_len, pad_len; + + *err = 0; + /* Verify that packet size with down-link header and mtu size */ + if (frm_len > cfv->mru || frm_len <= cfv->rx_hr + cfv->rx_tr) { + netdev_err(cfv->ndev, + "Invalid frmlen:%u mtu:%u hr:%d tr:%d\n", + frm_len, cfv->mru, cfv->rx_hr, + cfv->rx_tr); + *err = -EPROTO; + return NULL; + } + + cfpkt_len = frm_len - (cfv->rx_hr + cfv->rx_tr); + + pad_len = (unsigned long)(frm + cfv->rx_hr) & (IP_HDR_ALIGN - 1);
[PATCHv2 vringh 2/3] virtio: Add module driver macro for virtio drivers.
From: Sjur Brændeland Add helper macro for drivers that don't do anything special in module init/exit. Signed-off-by: Sjur Brændeland --- include/linux/virtio.h |9 + 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/include/linux/virtio.h b/include/linux/virtio.h index cf8adb1..00ccc40 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -126,4 +126,13 @@ static inline struct virtio_driver *drv_to_virtio(struct device_driver *drv) int register_virtio_driver(struct virtio_driver *drv); void unregister_virtio_driver(struct virtio_driver *drv); + +/* module_virtio_driver() - Helper macro for drivers that don't do + * anything special in module init/exit. This eliminates a lot of + * boilerplate. Each module may only use this macro once, and + * calling it replaces module_init() and module_exit() + */ +#define module_virtio_driver(__virtio_driver) \ + module_driver(__virtio_driver, register_virtio_driver, \ + unregister_virtio_driver) #endif /* _LINUX_VIRTIO_H */ -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCHv2 vringh 1/3] remoteproc: Add support for vringh (Host vrings)
From: Sjur Brændeland Add functions for creating, deleting and kicking host-side virtio rings. The host ring is not integrated with virtiqueues and cannot be managed through virtio-config. Remoteproc must export functions for handling the host-side virtio rings. The functions rproc_virtio_get_vringh(), rproc_virtio_del_vringh(), rproc_virtio_kick_vringh() are added to remoteproc_virtio.c. The existing functions rproc_vq_interrupt() and rproc_virtio_find_vqs() are updated to handle the new vhost rings. Signed-off-by: Sjur Brændeland cc: Ohad Ben-Cohen cc: Rusty Russell cc: Ido Yariv cc: Erwan Yvin --- drivers/remoteproc/Kconfig |3 + drivers/remoteproc/remoteproc_virtio.c | 127 ++-- include/linux/remoteproc.h | 14 3 files changed, 137 insertions(+), 7 deletions(-) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 96ce101..c7d1d36 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -7,6 +7,9 @@ config REMOTEPROC depends on HAS_DMA select FW_CONFIG select VIRTIO + select VHOST_RING + +source drivers/vhost/Kconfig config OMAP_REMOTEPROC tristate "OMAP remoteproc support" diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index 9e198e5..fa7bf7b 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -60,10 +61,15 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid) dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid); rvring = idr_find(&rproc->notifyids, notifyid); - if (!rvring || !rvring->vq) + if (!rvring) return IRQ_NONE; - return vring_interrupt(0, rvring->vq); + if (rvring->vringh && rvring->vringh_cb) + return rvring->vringh_cb(&rvring->rvdev->vdev, rvring->vringh); + else if (rvring->vq) + return vring_interrupt(0, rvring->vq); + else + return IRQ_NONE; } EXPORT_SYMBOL(rproc_vq_interrupt); @@ -149,14 +155,21 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, const char *names[]) { struct rproc *rproc = vdev_to_rproc(vdev); - int i, ret; + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + int rng, id, ret, nrings = ARRAY_SIZE(rvdev->vring); + + for (id = 0, rng = 0; rng < nrings; ++rng) { + struct rproc_vring *rvring = &rvdev->vring[rng]; + /* Skip the host side rings */ + if (rvring->vringh) + continue; - for (i = 0; i < nvqs; ++i) { - vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]); - if (IS_ERR(vqs[i])) { - ret = PTR_ERR(vqs[i]); + vqs[id] = rp_find_vq(vdev, rng, callbacks[id], names[id]); + if (IS_ERR(vqs[id])) { + ret = PTR_ERR(vqs[id]); goto error; } + ++id; } /* now that the vqs are all set, boot the remote processor */ @@ -173,6 +186,106 @@ error: return ret; } +/** + * rproc_virtio_new_vringh() - create a reversed virtio ring. + * @vdev: the virtio device + * @index: the virtio ring index + * @cb: callback for the reversed virtio ring + * + * This function should be called by the virtio-driver + * before calling find_vqs(). It returns a struct vringh for + * accessing the virtio ring. + * + * Return: struct vhost, or NULL upon error. + */ +struct vringh * +rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index, + irqreturn_t (*cb)(struct virtio_device *vdev, + struct vringh *vring)) +{ + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct rproc_vring *rvring; + struct vringh *vrh; + int err; + + if (index > ARRAY_SIZE(rvdev->vring)) { + dev_err(&rvdev->vdev.dev, "bad vring index: %d\n", index); + return NULL; + } + + vrh = kzalloc(sizeof(*vrh), GFP_KERNEL); + if (!vrh) + return NULL; + + err = rproc_alloc_vring(rvdev, index); + if (err) + goto free_vring; + + + rvring = &rvdev->vring[index]; + /* zero vring */ + memset(rvring->va, 0, vring_size(rvring->len, rvring->align)); + vring_init(&vrh->vring, rvring->len, rvring->va, rvring->align); + + rvring->vringh_cb = cb; + rvring->vringh = vrh; + + err = vringh_init_kern(vrh, + rvdev->dfeatures, + rvring->len, + false, + vrh->vring.desc, + vrh->vring.
[PATCHv2 vringh 0/3] Introduce CAIF Virtio driver
From: Sjur Brændeland This driver depends on Rusty's new host virtio ring implementation, so this patch-set is based on the vringh branch in Rusty's git. Changes since V1: - Use the new iov helper functions, and simplify iov handling. However this triggers compile warnings, as it takes struct iov while kernel api uses struct kiov - Introduced the module_virtio_driver macro - Pass NULL as wiov to vringh_getdesc_kern() Regards, Sjur Sjur Brændeland (2): remoteproc: Add support for vringh (Host vrings) virtio: Add module driver macro for virtio drivers. Vikram ARV (1): caif_virtio: Introduce caif over virtio drivers/net/caif/Kconfig |8 + drivers/net/caif/Makefile |3 + drivers/net/caif/caif_virtio.c | 547 drivers/remoteproc/Kconfig |3 + drivers/remoteproc/remoteproc_virtio.c | 127 +++- include/linux/remoteproc.h | 14 + include/linux/virtio.h |9 + include/linux/virtio_caif.h| 24 ++ include/uapi/linux/virtio_ids.h|1 + 9 files changed, 729 insertions(+), 7 deletions(-) create mode 100644 drivers/net/caif/caif_virtio.c create mode 100644 include/linux/virtio_caif.h -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH] virtio: Add module driver macro for virtio drivers.
From: Sjur Brændeland Add helper macro for drivers that don't do anything special in module init/exit. Signed-off-by: Sjur Brændeland --- Hi Rusty, Here is the patch for module driver macro. I will update caif_virtio accordingly in my next patch-set. Thanks, Sjur include/linux/virtio.h |9 + 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/include/linux/virtio.h b/include/linux/virtio.h index cf8adb1..00ccc40 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -126,4 +126,13 @@ static inline struct virtio_driver *drv_to_virtio(struct device_driver *drv) int register_virtio_driver(struct virtio_driver *drv); void unregister_virtio_driver(struct virtio_driver *drv); + +/* module_virtio_driver() - Helper macro for drivers that don't do + * anything special in module init/exit. This eliminates a lot of + * boilerplate. Each module may only use this macro once, and + * calling it replaces module_init() and module_exit() + */ +#define module_virtio_driver(__virtio_driver) \ + module_driver(__virtio_driver, register_virtio_driver, \ + unregister_virtio_driver) #endif /* _LINUX_VIRTIO_H */ -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH vringh 2/2] caif_virtio: Introduce caif over virtio
From: Vikram ARV Add the the Virtio shared memory driver for STE Modems. caif_virtio is implemented utilizing the virtio framework for data transport and is managed with the remoteproc frameworks. The Virtio queue is used for transmitting data to the modem, and the new vringh implementation is receiving data over the vring. Signed-off-by: Vikram ARV Signed-off-by: Sjur Brændeland to: David S. Miller cc: Rusty Russell cc: Ohad Ben-Cohen cc: Ido Yariv cc: Erwan Yvin --- Hi Dave, Rusty has accepted to take this patch via his tree. Feedback and review comments are appreciated. Thanks, Sjur drivers/net/caif/Kconfig|8 + drivers/net/caif/Makefile |3 + drivers/net/caif/caif_virtio.c | 568 +++ include/linux/virtio_caif.h | 24 ++ include/uapi/linux/virtio_ids.h |1 + 5 files changed, 604 insertions(+), 0 deletions(-) create mode 100644 drivers/net/caif/caif_virtio.c create mode 100644 include/linux/virtio_caif.h diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig index abf4d7a..a8b67e9 100644 --- a/drivers/net/caif/Kconfig +++ b/drivers/net/caif/Kconfig @@ -47,3 +47,11 @@ config CAIF_HSI The caif low level driver for CAIF over HSI. Be aware that if you enable this then you also need to enable a low-level HSI driver. + +config CAIF_VIRTIO + tristate "CAIF virtio transport driver" + depends on CAIF + depends on REMOTEPROC + default n + ---help--- + The caif driver for CAIF over Virtio. diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile index 91dff86..d9ee26a 100644 --- a/drivers/net/caif/Makefile +++ b/drivers/net/caif/Makefile @@ -13,3 +13,6 @@ obj-$(CONFIG_CAIF_SHM) += caif_shm.o # HSI interface obj-$(CONFIG_CAIF_HSI) += caif_hsi.o + +# Virtio interface +obj-$(CONFIG_CAIF_VIRTIO) += caif_virtio.o diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c new file mode 100644 index 000..e8ea114 --- /dev/null +++ b/drivers/net/caif/caif_virtio.c @@ -0,0 +1,568 @@ +/* + * Copyright (C) ST-Ericsson AB 2012 + * Contact: Sjur Brendeland / sjur.brandel...@stericsson.com + * Authors: Vicram Arv / vikram@stericsson.com, + * Dmitry Tarnyagin / dmitry.tarnya...@stericsson.com + * Sjur Brendeland / sjur.brandel...@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Vicram Arv "); +MODULE_AUTHOR("Sjur Brendeland riov.allocated) { + kfree(ctx->riov.iov); + ctx->riov.iov = NULL; + ctx->riov.allocated = false; + } + ctx->riov.iov = NULL; + ctx->riov.i = 0; + ctx->riov.max = 0; +} + +static void cfv_release_cb(struct virtqueue *vq_tx) +{ + struct cfv_info *cfv = vq_tx->vdev->priv; + tasklet_schedule(&cfv->tx_release_tasklet); +} + +/* This is invoked whenever the remote processor completed processing + * a TX msg we just sent it, and the buffer is put back to the used ring. + */ +static void cfv_release_used_buf(struct virtqueue *vq_tx) +{ + struct cfv_info *cfv = vq_tx->vdev->priv; + unsigned long flags; + + BUG_ON(vq_tx != cfv->vq_tx); + WARN_ON_ONCE(irqs_disabled()); + + for (;;) { + unsigned int len; + struct token_info *buf_info; + + /* Get used buffer from used ring to recycle used descriptors */ + spin_lock_irqsave(&cfv->tx_lock, flags); + buf_info = virtqueue_get_buf(vq_tx, &len); + + if (!buf_info) + goto out; + + BUG_ON(!cfv->queued_tx); + if (--cfv->queued_tx <= cfv->watermark_tx) { + cfv->watermark_tx = 0; + netif_tx_wake_all_queues(cfv->ndev); + } + spin_unlock_irqrestore(&cfv->tx_lock, flags); + + dma_free_coherent(vq_tx->vdev->dev.parent->parent, + buf_info->size, buf_info->vaddr, + buf_info->dma_handle); + kfree(buf_info); + } + return; +out: + spin_unlock_irqrestore(&cfv->tx_lock, flags); +} + +static struct sk_buff *cfv_alloc_and_copy_skb(int *err, + struct cfv_info *cfv, + u8 *frm, u32 frm_len) +{ + struct sk_buff *skb; + u32 cfpkt_len, pad_len; + + *err = 0; + /* Verify that packet size with down-link header and mtu size */ + if (frm_len > cfv->mru || frm_len <= cfv->rx_hr + cfv->rx_tr) { + netdev_err(cfv->ndev, + "Invalid frmlen:%u mtu:%u hr:%d tr:%d\n", + frm_len, cfv->mru, c
[PATCH vringh 1/2] remoteproc: Add support for vringh (Host vrings)
From: Sjur Brændeland Add functions for creating, deleting and kicking host-side virtio rings. The host ring is not integrated with virtiqueues and cannot be managed through virtio-config. Remoteproc must export functions for handling the host-side virtio rings. The functions rproc_virtio_get_vringh(), rproc_virtio_del_vringh(), rproc_virtio_kick_vringh() are added to remoteproc_virtio.c. The existing functions rproc_vq_interrupt() and rproc_virtio_find_vqs() are updated to handle the new vhost rings. Signed-off-by: Sjur Brændeland cc: Ohad Ben-Cohen cc: Rusty Russell cc: Ido Yariv cc: Erwan Yvin --- Hi Ohad, I would really appreciate if you could find time to review this patch. It will go via Rusty's vringh tree. Feedback and review comments are welcomed. Thanks, Sjur drivers/remoteproc/Kconfig |3 + drivers/remoteproc/remoteproc_virtio.c | 127 ++-- include/linux/remoteproc.h | 14 3 files changed, 137 insertions(+), 7 deletions(-) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 96ce101..c7d1d36 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -7,6 +7,9 @@ config REMOTEPROC depends on HAS_DMA select FW_CONFIG select VIRTIO + select VHOST_RING + +source drivers/vhost/Kconfig config OMAP_REMOTEPROC tristate "OMAP remoteproc support" diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index 9e198e5..fa7bf7b 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -60,10 +61,15 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid) dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid); rvring = idr_find(&rproc->notifyids, notifyid); - if (!rvring || !rvring->vq) + if (!rvring) return IRQ_NONE; - return vring_interrupt(0, rvring->vq); + if (rvring->vringh && rvring->vringh_cb) + return rvring->vringh_cb(&rvring->rvdev->vdev, rvring->vringh); + else if (rvring->vq) + return vring_interrupt(0, rvring->vq); + else + return IRQ_NONE; } EXPORT_SYMBOL(rproc_vq_interrupt); @@ -149,14 +155,21 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, const char *names[]) { struct rproc *rproc = vdev_to_rproc(vdev); - int i, ret; + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + int rng, id, ret, nrings = ARRAY_SIZE(rvdev->vring); + + for (id = 0, rng = 0; rng < nrings; ++rng) { + struct rproc_vring *rvring = &rvdev->vring[rng]; + /* Skip the host side rings */ + if (rvring->vringh) + continue; - for (i = 0; i < nvqs; ++i) { - vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]); - if (IS_ERR(vqs[i])) { - ret = PTR_ERR(vqs[i]); + vqs[id] = rp_find_vq(vdev, rng, callbacks[id], names[id]); + if (IS_ERR(vqs[id])) { + ret = PTR_ERR(vqs[id]); goto error; } + ++id; } /* now that the vqs are all set, boot the remote processor */ @@ -173,6 +186,106 @@ error: return ret; } +/** + * rproc_virtio_new_vringh() - create a reversed virtio ring. + * @vdev: the virtio device + * @index: the virtio ring index + * @cb: callback for the reversed virtio ring + * + * This function should be called by the virtio-driver + * before calling find_vqs(). It returns a struct vringh for + * accessing the virtio ring. + * + * Return: struct vhost, or NULL upon error. + */ +struct vringh * +rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index, + irqreturn_t (*cb)(struct virtio_device *vdev, + struct vringh *vring)) +{ + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct rproc_vring *rvring; + struct vringh *vrh; + int err; + + if (index > ARRAY_SIZE(rvdev->vring)) { + dev_err(&rvdev->vdev.dev, "bad vring index: %d\n", index); + return NULL; + } + + vrh = kzalloc(sizeof(*vrh), GFP_KERNEL); + if (!vrh) + return NULL; + + err = rproc_alloc_vring(rvdev, index); + if (err) + goto free_vring; + + + rvring = &rvdev->vring[index]; + /* zero vring */ + memset(rvring->va, 0, vring_size(rvring->len, rvring->align)); + vring_init(&vrh->vring, rvring->len, rvring->va, rvring->align); + + rvring->vringh_cb = cb; + rvring->vringh = vrh; + + err = vringh_init_kern(vrh, + rvdev->dfeat
[PATCH vringh 0/2] Introduce CAIF Virtio driver
From: Sjur Brændeland This patch-set introduces the CAIF Virtio Link layer driver. This driver depends on Rusty's new host virtio ring implementation, so this patch-set is based on the vringh branch in Rusty's git. Regards, Sjur cc: Rusty Russell cc: Ohad Ben-Cohen cc: David S. Miller cc: Ido Yariv cc: Erwan Yvin Sjur Brændeland (1): remoteproc: Add support for vringh (Host vrings) Vikram ARV (1): caif_virtio: Introduce caif over virtio drivers/net/caif/Kconfig |8 + drivers/net/caif/Makefile |3 + drivers/net/caif/caif_virtio.c | 568 drivers/remoteproc/Kconfig |3 + drivers/remoteproc/remoteproc_virtio.c | 127 +++- include/linux/remoteproc.h | 14 + include/linux/virtio_caif.h| 24 ++ include/uapi/linux/virtio_ids.h|1 + 8 files changed, 741 insertions(+), 7 deletions(-) create mode 100644 drivers/net/caif/caif_virtio.c create mode 100644 include/linux/virtio_caif.h -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[RFC] remoteproc: Add support for host-side (reversed) vrings
From: Sjur Brændeland Hi Ohad, Ido and Rusty. Rusty has implemented host-side virtio ring. I will be using vringh for the caif_virtio driver. But we need to figure out how to integrate the vringh into remoteproc. Below is my initial stab on this. This code is completely untested, but I'd love to get some initial feedback on this. Ohad/Ido are you happy with this approach? More code will follow after some test and debugging... Regards, Sjur -- remoteproc: Add support for host-side (reversed) vrings Add functions for creating, deleting and kicking host-side virtio rings. The host ring is not integrated with virtiqueues and cannot be managed through virtio-config. So the virtio drivers must call functions exported from remoteproc for handling the host-side virtio rings. The functions rproc_virtio_get_vringh(), rproc_virtio_del_vringh(), rproc_virtio_kick_vringh() are added to remoteproc_virtio.c. The existing functions rproc_vq_interrupt() and rproc_virtio_find_vqs() are updated to handle the new vhost rings. Signed-off-by: Sjur Brændeland --- drivers/remoteproc/remoteproc_virtio.c | 116 ++-- include/linux/remoteproc.h | 14 2 files changed, 124 insertions(+), 6 deletions(-) diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index 9e198e5..1928433 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -63,7 +64,10 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid) if (!rvring || !rvring->vq) return IRQ_NONE; - return vring_interrupt(0, rvring->vq); + if (rvring->vringh && rvring->vringh_cb) + return rvring->vringh_cb(&rvring->rvdev->vdev, rvring->vringh); + else + return vring_interrupt(0, rvring->vq); } EXPORT_SYMBOL(rproc_vq_interrupt); @@ -149,14 +153,21 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, const char *names[]) { struct rproc *rproc = vdev_to_rproc(vdev); - int i, ret; + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + int rng, id, ret, nrings = ARRAY_SIZE(rvdev->vring); + + for (id = 0, rng = 0; rng < nrings; ++rng) { + struct rproc_vring *rvring = &rvdev->vring[rng]; + /* Skip the host side rings */ + if (rvring->vringh) + continue; - for (i = 0; i < nvqs; ++i) { - vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]); - if (IS_ERR(vqs[i])) { - ret = PTR_ERR(vqs[i]); + vqs[id] = rp_find_vq(vdev, rng, callbacks[id], names[id]); + if (IS_ERR(vqs[id])) { + ret = PTR_ERR(vqs[id]); goto error; } + ++id; } /* now that the vqs are all set, boot the remote processor */ @@ -173,6 +184,99 @@ error: return ret; } +/** + * rproc_virtio_new_vringh() - create a reversed virtio ring. + * @vdev: the virtio device + * @index: the virtio ring index + * @cb: callback for the reversed virtio ring + * + * This function should be called by the virtio-driver + * before calling find_vqs(). It returns a struct vringh for + * accessing the virtio ring. + * + * Return: struct vhost, or NULL upon error. + */ +struct vringh * +rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index, + irqreturn_t (*cb)(struct virtio_device *vdev, + struct vringh *vring)) +{ + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct rproc_vring *rvring; + struct vringh *vrh; + int err; + + if (index > ARRAY_SIZE(rvdev->vring)) { + dev_err(&rvdev->vdev.dev, "bad vring index: %d\n", index); + return NULL; + } + + vrh = kzalloc(sizeof(*vrh), GFP_KERNEL); + if (!vrh) + return NULL; + + + rvring = &rvdev->vring[index]; + vring_init(&vrh->vring, rvring->len, rvring->va, rvring->align); + /* zero vring */ + memset(&vrh->vring, 0, vring_size(rvring->len, rvring->align)); + rvring->vringh_cb = cb; + rvring->vringh = vrh; + + err = vringh_init_kern(vrh, + rvdev->dfeatures, + rvring->len, + false, + vrh->vring.desc, + vrh->vring.avail, + vrh->vring.used); + if (err) { + dev_err(&vdev->dev, "failed to create vhost: %d\n", err); + kfree(vrh); + vrh = NULL; + } + + return vrh; +} +EXPORT_SYMBOL(rproc_virtio_get_vringh); + +/** + * rproc_virtio_del_vri
[RFC] virtio_console: Add DRIVER and INTERFACE to uevent.
From: Sjur Brændeland Add information so rproc-serial can be easily recogniced from user space. Add the following information to uevent: DRIVER=virtio_console|virtio_rproc_serial INTERFACE=grand-parent/parent/name Signed-off-by: Sjur Brændeland --- Hi, I need some way to identify the major/minor number for the rproc-serial device, given the udev event. Review comments are welcomed. Thanks, Sjur drivers/char/virtio_console.c | 22 ++ 1 files changed, 22 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 031be0b..96c5ed9 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -2190,6 +2190,27 @@ static struct virtio_driver virtio_rproc_serial = { .remove = virtcons_remove, }; +int class_virtio_ports_uevent(struct device *_dev, struct kobj_uevent_env *env) +{ + struct port *port = dev_get_drvdata(_dev); + struct device *dev; + int err; + + if (!port || !port->portdev || !port->portdev->vdev) + return 0; + + dev = &port->portdev->vdev->dev; + err = add_uevent_var(env, "DRIVER=%s", dev->driver->name); + if (err) + return err; + + return add_uevent_var(env, "INTERFACE=%s/%s/%s", + dev->parent->parent ? + dev_name(dev->parent->parent) : "", + dev->parent ? dev_name(dev->parent) : "", + dev_name(dev)); +} + static int __init init(void) { int err; @@ -2201,6 +,7 @@ static int __init init(void) return err; } + pdrvdata.class->dev_uevent = class_virtio_ports_uevent; pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); if (!pdrvdata.debugfs_dir) { pr_warning("Error %ld creating debugfs dir for virtio-ports\n", -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH] virtio_console: Use virtio device index to generate port name
From: Sjur Brændeland Use virtio device index for creating unique device port names. Current index allocation in virtio is based on a monotonically increasing variable "index". A better handling of this is to use device index which is allocated by ida. Signed-off-by: Sjur Brændeland --- drivers/char/virtio_console.c | 16 +++- 1 files changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index c17b053..031be0b 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -61,9 +61,6 @@ struct ports_driver_data { /* List of all the devices we're handling */ struct list_head portdevs; - /* Number of devices this driver is handling */ - unsigned int index; - /* * This is used to keep track of the number of hvc consoles * spawned by this driver. This number is given as the first @@ -169,9 +166,6 @@ struct ports_device { /* Array of per-port IO virtqueues */ struct virtqueue **in_vqs, **out_vqs; - /* Used for numbering devices for sysfs and debugfs */ - unsigned int drv_index; - /* Major number for this device. Ports will be created as minors. */ int chr_major; }; @@ -1415,7 +1409,7 @@ static int add_port(struct ports_device *portdev, u32 id) } port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, devt, port, "vport%up%u", - port->portdev->drv_index, id); + port->portdev->vdev->index, id); if (IS_ERR(port->dev)) { err = PTR_ERR(port->dev); dev_err(&port->portdev->vdev->dev, @@ -1470,7 +1464,7 @@ static int add_port(struct ports_device *portdev, u32 id) * inspect a port's state at any time */ sprintf(debugfs_name, "vport%up%u", - port->portdev->drv_index, id); + port->portdev->vdev->index, id); port->debugfs_file = debugfs_create_file(debugfs_name, 0444, pdrvdata.debugfs_dir, port, @@ -1961,16 +1955,12 @@ static int virtcons_probe(struct virtio_device *vdev) portdev->vdev = vdev; vdev->priv = portdev; - spin_lock_irq(&pdrvdata_lock); - portdev->drv_index = pdrvdata.index++; - spin_unlock_irq(&pdrvdata_lock); - portdev->chr_major = register_chrdev(0, "virtio-portsdev", &portdev_fops); if (portdev->chr_major < 0) { dev_err(&vdev->dev, "Error %d registering chrdev for device %u\n", - portdev->chr_major, portdev->drv_index); + portdev->chr_major, vdev->index); err = portdev->chr_major; goto free; } -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH] virtio_console: Let unconnected rproc device receive data.
From: Sjur Brændeland Allow rproc serial ports to receive data before the port is connected. Rproc serial ports usually talk to very simple remote devices with no control queue managing open/close events. So we must let remote devices write to the virtio ring even if the device is not yet fully initialized. Signed-off-by: Sjur Brændeland --- This patch is intended for v3.9. Thanks, Sjur drivers/char/virtio_console.c |5 - 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index ee4dbea..c17b053 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1763,8 +1763,11 @@ static void in_intr(struct virtqueue *vq) * tty is spawned) and the host sends out data to console * ports. For generic serial ports, the host won't * (shouldn't) send data till the guest is connected. +* However a remote device might send data before the port is +* connected. So don't remove data from a rproc_serial device. */ - if (!port->guest_connected) + + if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev)) discard_port_data(port); spin_unlock_irqrestore(&port->inbuf_lock, flags); -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH] virtio_console: Don't access uninitialized data.
From: Sjur Brændeland Don't access uninitialized work-queue when removing device. The work queue is initialized only if the device multi-queue. So don't call cancel_work unless this is a multi-queue device. This fixes the following panic: Kernel panic - not syncing: BUG! Call Trace: 62031b28: [<6026085d>] panic+0x16b/0x2d3 62031b30: [<6004ef5e>] flush_work+0x0/0x1d7 62031b60: [<602606f2>] panic+0x0/0x2d3 62031b68: [<600333b0>] memcpy+0x0/0x140 62031b80: [<6002d58a>] unblock_signals+0x0/0x84 62031ba0: [<602609c5>] printk+0x0/0xa0 62031bd8: [<60264e51>] __mutex_unlock_slowpath+0x13d/0x148 62031c10: [<6004ef5e>] flush_work+0x0/0x1d7 62031c18: [<60050234>] try_to_grab_pending+0x0/0x17e 62031c38: [<6004e984>] get_work_gcwq+0x71/0x8f 62031c48: [<60050539>] __cancel_work_timer+0x5b/0x115 62031c78: [<628acc85>] unplug_port+0x0/0x191 [virtio_console] 62031c98: [<6005061c>] cancel_work_sync+0x12/0x14 62031ca8: [<628ace96>] virtcons_remove+0x80/0x15c [virtio_console] 62031ce8: [<628191de>] virtio_dev_remove+0x1e/0x7e [virtio] 62031d08: [<601cf242>] __device_release_driver+0x75/0xe4 62031d28: [<601cf2dd>] device_release_driver+0x2c/0x40 62031d48: [<601ce0dd>] driver_unbind+0x7d/0xc6 62031d88: [<601cd5d9>] drv_attr_store+0x27/0x29 62031d98: [<60115f61>] sysfs_write_file+0x100/0x14d 62031df8: [<600b737d>] vfs_write+0xcb/0x184 62031e08: [<600b58b8>] filp_close+0x88/0x94 62031e38: [<600b7686>] sys_write+0x59/0x88 62031e88: [<6001ced1>] handle_syscall+0x5d/0x80 62031ea8: [<60030a74>] userspace+0x405/0x531 62031f08: [<600d32cc>] sys_dup+0x0/0x5e 62031f28: [<601b11d6>] strcpy+0x0/0x18 62031f38: [<600be46c>] do_execve+0x10/0x12 62031f48: [<600184c7>] run_init_process+0x43/0x45 62031fd8: [<60019a91>] new_thread_handler+0xba/0xbc Signed-off-by: Sjur Brændeland --- This fix is intended of v3.8. Thanks, Sjur drivers/char/virtio_console.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 684b0d5..ee4dbea 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -2062,7 +2062,8 @@ static void virtcons_remove(struct virtio_device *vdev) /* Disable interrupts for vqs */ vdev->config->reset(vdev); /* Finish up work that's lined up */ - cancel_work_sync(&portdev->control_work); + if (use_multiport(portdev)) + cancel_work_sync(&portdev->control_work); list_for_each_entry_safe(port, port2, &portdev->ports, list) unplug_port(port); -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH resend] virtio_console: Free buffers from out-queue upon close
From: Sjur Brændeland Free pending output buffers from the virtio out-queue when host has acknowledged port_close. Also removed WARN_ON() in remove_port_data(). Signed-off-by: Sjur Brændeland --- Resending, this time including a proper "Subject"... -- Hi Amit, Note: This patch is compile tested only. I have done the removal of buffers from out-queue in handle_control_message() when host has acked the close request. This seems less racy than doing it in the release function. I you want to change this further, feel free to take over from here and refine this. Thanks, Sjur drivers/char/virtio_console.c | 14 ++ 1 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 3fa036a..3a5831d 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1522,15 +1522,9 @@ static void remove_port_data(struct port *port) while ((buf = virtqueue_detach_unused_buf(port->in_vq))) free_buf(buf, true); - /* -* Check the out-queue for buffers. For VIRTIO_CONSOLE it is a -* bug if this happens. But for RPROC_SERIAL the remote processor -* may have crashed, leaving buffers hanging in the out-queue. -*/ - while ((buf = virtqueue_detach_unused_buf(port->out_vq))) { - WARN_ON_ONCE(!is_rproc_serial(port->portdev->vdev)); + /* Free pending buffers from the out-queue. */ + while ((buf = virtqueue_detach_unused_buf(port->out_vq))) free_buf(buf, true); - } } /* @@ -1655,6 +1649,10 @@ static void handle_control_message(struct ports_device *portdev, */ spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); + + /* Free pending buffers from the out-queue. */ + while ((buf = virtqueue_detach_unused_buf(port->out_vq))) + free_buf(buf, true); spin_unlock_irq(&port->outvq_lock); /* -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[no subject]
From 0ce16d6a0270daebd9972e94a834034a093228b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Date: Wed, 7 Nov 2012 12:20:07 +0100 Subject: [PATCH] virtio_console:Free buffers from out-queue upon close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Free pending output buffers from the virtio out-queue when host has acknowledged port_close. Also removed WARN_ON() in remove_port_data(). Signed-off-by: Sjur Brændeland --- Hi Amit, Note: This patch is compile tested only. I have done the removal of buffers from out-queue in handle_control_message() when host has acked the close request. This seems less racy than doing it in the release function. I you want to change this further, feel free to take over from here and refine this. Thanks, Sjur drivers/char/virtio_console.c | 14 ++ 1 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 3fa036a..3a5831d 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1522,15 +1522,9 @@ static void remove_port_data(struct port *port) while ((buf = virtqueue_detach_unused_buf(port->in_vq))) free_buf(buf, true); - /* -* Check the out-queue for buffers. For VIRTIO_CONSOLE it is a -* bug if this happens. But for RPROC_SERIAL the remote processor -* may have crashed, leaving buffers hanging in the out-queue. -*/ - while ((buf = virtqueue_detach_unused_buf(port->out_vq))) { - WARN_ON_ONCE(!is_rproc_serial(port->portdev->vdev)); + /* Free pending buffers from the out-queue. */ + while ((buf = virtqueue_detach_unused_buf(port->out_vq))) free_buf(buf, true); - } } /* @@ -1655,6 +1649,10 @@ static void handle_control_message(struct ports_device *portdev, */ spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); + + /* Free pending buffers from the out-queue. */ + while ((buf = virtqueue_detach_unused_buf(port->out_vq))) + free_buf(buf, true); spin_unlock_irq(&port->outvq_lock); /* -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCHv7 4/4] virtio_console: Add support for remoteproc serial
From: Sjur Brændeland Add a simple serial connection driver called VIRTIO_ID_RPROC_SERIAL (11) for communicating with a remote processor in an asymmetric multi-processing configuration. This implementation reuses the existing virtio_console implementation, and adds support for DMA allocation of data buffers and disables use of tty console and the virtio control queue. Signed-off-by: Sjur Brændeland --- drivers/char/virtio_console.c | 201 - include/linux/virtio_ids.h|1 + 2 files changed, 180 insertions(+), 22 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 917cc830..eeb9b35 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -37,8 +37,12 @@ #include #include #include +#include +#include #include "../tty/hvc/hvc_console.h" +#define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC) + /* * This is a global struct for storing common data for all the devices * this driver handles. @@ -112,6 +116,15 @@ struct port_buffer { /* offset in the buf from which to consume data */ size_t offset; + /* DMA address of buffer */ + dma_addr_t dma; + + /* Device we got DMA memory from */ + struct device *dev; + + /* List of pending dma buffers to free */ + struct list_head list; + /* If sgpages == 0 then buf is used */ unsigned int sgpages; @@ -331,6 +344,11 @@ static bool is_console_port(struct port *port) return false; } +static bool is_rproc_serial(const struct virtio_device *vdev) +{ + return is_rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL; +} + static inline bool use_multiport(struct ports_device *portdev) { /* @@ -342,11 +360,13 @@ static inline bool use_multiport(struct ports_device *portdev) return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); } -static void free_buf(struct port_buffer *buf) +static DEFINE_SPINLOCK(dma_bufs_lock); +static LIST_HEAD(pending_free_dma_bufs); + +static void free_buf(struct port_buffer *buf, bool can_sleep) { unsigned int i; - kfree(buf->buf); for (i = 0; i < buf->sgpages; i++) { struct page *page = sg_page(&buf->sg[i]); if (!page) @@ -354,14 +374,58 @@ static void free_buf(struct port_buffer *buf) put_page(page); } + if (!buf->dev) { + kfree(buf->buf); + } else if (is_rproc_enabled) { + unsigned long flags; + + /* dma_free_coherent requires interrupts to be enabled. */ + if (!can_sleep) { + /* queue up dma-buffers to be freed later */ + spin_lock_irqsave(&dma_bufs_lock, flags); + list_add_tail(&buf->list, &pending_free_dma_bufs); + spin_unlock_irqrestore(&dma_bufs_lock, flags); + return; + } + dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma); + + /* Release device refcnt and allow it to be freed */ + put_device(buf->dev); + } + kfree(buf); } +static void reclaim_dma_bufs(void) +{ + unsigned long flags; + struct port_buffer *buf, *tmp; + LIST_HEAD(tmp_list); + + if (list_empty(&pending_free_dma_bufs)) + return; + + /* Create a copy of the pending_free_dma_bufs while holding the lock */ + spin_lock_irqsave(&dma_bufs_lock, flags); + list_cut_position(&tmp_list, &pending_free_dma_bufs, + pending_free_dma_bufs.prev); + spin_unlock_irqrestore(&dma_bufs_lock, flags); + + /* Release the dma buffers, without irqs enabled */ + list_for_each_entry_safe(buf, tmp, &tmp_list, list) { + list_del(&buf->list); + free_buf(buf, true); + } +} + static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, int pages) { struct port_buffer *buf; + if (is_rproc_serial(vq->vdev)) + reclaim_dma_bufs(); + /* * Allocate buffer and the sg list. The sg list array is allocated * directly after the port_buffer struct. @@ -373,11 +437,34 @@ static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, buf->sgpages = pages; if (pages > 0) { + buf->dev = NULL; buf->buf = NULL; return buf; } - buf->buf = kmalloc(buf_size, GFP_KERNEL); + if (is_rproc_serial(vq->vdev)) { + /* +* 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. +* The code here would
[PATCHv7 3/4] virtio_console: Merge struct buffer_token into struct port_buffer
From: Sjur Brændeland Refactoring the splice functionality by unifying the approach for sending scatter-lists and regular buffers. This simplifies buffer handling and reduces code size. Splice will now allocate a port_buffer and send_buf() and free_buf() can always be used for any buffer. Signed-off-by: Sjur Brændeland --- drivers/char/virtio_console.c | 131 + 1 files changed, 55 insertions(+), 76 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 301d17e..917cc830 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -111,6 +111,12 @@ struct port_buffer { size_t len; /* offset in the buf from which to consume data */ size_t offset; + + /* If sgpages == 0 then buf is used */ + unsigned int sgpages; + + /* sg is used if spages > 0. sg must be the last in is struct */ + struct scatterlist sg[0]; }; /* @@ -338,17 +344,39 @@ static inline bool use_multiport(struct ports_device *portdev) static void free_buf(struct port_buffer *buf) { + unsigned int i; + kfree(buf->buf); + for (i = 0; i < buf->sgpages; i++) { + struct page *page = sg_page(&buf->sg[i]); + if (!page) + break; + put_page(page); + } + kfree(buf); } -static struct port_buffer *alloc_buf(size_t buf_size) +static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, +int pages) { struct port_buffer *buf; - buf = kmalloc(sizeof(*buf), GFP_KERNEL); + /* +* Allocate buffer and the sg list. The sg list array is allocated +* directly after the port_buffer struct. +*/ + buf = kmalloc(sizeof(*buf) + sizeof(struct scatterlist) * pages, + GFP_KERNEL); if (!buf) goto fail; + + buf->sgpages = pages; + if (pages > 0) { + buf->buf = NULL; + return buf; + } + buf->buf = kmalloc(buf_size, GFP_KERNEL); if (!buf->buf) goto free_buf; @@ -476,52 +504,26 @@ static ssize_t send_control_msg(struct port *port, unsigned int event, return 0; } -struct buffer_token { - union { - void *buf; - struct scatterlist *sg; - } u; - /* If sgpages == 0 then buf is used, else sg is used */ - unsigned int sgpages; -}; - -static void reclaim_sg_pages(struct scatterlist *sg, unsigned int nrpages) -{ - int i; - struct page *page; - - for (i = 0; i < nrpages; i++) { - page = sg_page(&sg[i]); - if (!page) - break; - put_page(page); - } - kfree(sg); -} /* Callers must take the port->outvq_lock */ static void reclaim_consumed_buffers(struct port *port) { - struct buffer_token *tok; + struct port_buffer *buf; unsigned int len; if (!port->portdev) { /* Device has been unplugged. vqs are already gone. */ return; } - while ((tok = virtqueue_get_buf(port->out_vq, &len))) { - if (tok->sgpages) - reclaim_sg_pages(tok->u.sg, tok->sgpages); - else - kfree(tok->u.buf); - kfree(tok); + while ((buf = virtqueue_get_buf(port->out_vq, &len))) { + free_buf(buf); port->outvq_full = false; } } static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, int nents, size_t in_count, - struct buffer_token *tok, bool nonblock) + void *data, bool nonblock) { struct virtqueue *out_vq; ssize_t ret; @@ -534,7 +536,7 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, reclaim_consumed_buffers(port); - ret = virtqueue_add_buf(out_vq, sg, nents, 0, tok, GFP_ATOMIC); + ret = virtqueue_add_buf(out_vq, sg, nents, 0, data, GFP_ATOMIC); /* Tell Host to go! */ virtqueue_kick(out_vq); @@ -572,37 +574,6 @@ done: return in_count; } -static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, - bool nonblock) -{ - struct scatterlist sg[1]; - struct buffer_token *tok; - - tok = kmalloc(sizeof(*tok), GFP_ATOMIC); - if (!tok) - return -ENOMEM; - tok->sgpages = 0; - tok->u.buf = in_buf; - - sg_init_one(sg, in_buf, in_count); - - return __send_to_port(port, sg, 1, in_count, tok, nonblock); -} - -static ssize_t send_pages(struct port *port, struct scatterlist *sg, int nents, - size_t in_count, bool nonblock) -{ - struct buffer_token *tok; - - tok = kmalloc(si
[PATCHv7 2/4] virtio_console: Use kmalloc instead of kzalloc
From: Sjur Brændeland Avoid the more cpu expensive kzalloc when allocating buffers. Originally kzalloc was intended for isolating the guest from the host by not sending random guest data to the host. But device isolation is not yet in place so kzalloc is not really needed. Signed-off-by: Sjur Brændeland --- drivers/char/virtio_console.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index c36b2f6..301d17e 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -349,7 +349,7 @@ static struct port_buffer *alloc_buf(size_t buf_size) buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); + buf->buf = kmalloc(buf_size, GFP_KERNEL); if (!buf->buf) goto free_buf; buf->len = 0; -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCHv7 1/4] virtio_console: Free buffer if splice fails
From: Sjur Brændeland Free the allocated scatter list if send_pages fails in function port_splice_write. Signed-off-by: Sjur Brændeland --- drivers/char/virtio_console.c |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8ab9c3d..c36b2f6 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -879,6 +879,8 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, if (likely(ret > 0)) ret = send_pages(port, sgl.sg, sgl.n, sgl.len, true); + if (unlikely(ret <= 0)) + kfree(sgl.sg); return ret; } -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCHv7 0/4] virtio_console: Add rproc_serial driver
From: Sjur Brændeland This patch-set introduces a new virtio type "rproc_serial" for communicating with remote processors over shared memory. The driver depends on the the remoteproc framework. As preparation for introducing "rproc_serial" I've done a refactoring of the transmit buffer handling. This patch-set is a rework of the patch-set from Sept 25th, hopefully all review comments has been addressed. The fist patch is a bugfix and migth be applicable for 3.7. Thanks, Sjur Sjur Brændeland (4): virtio_console: Free buffer if splice fails virtio_console: Use kmalloc instead of kzalloc virtio_console: Merge struct buffer_token into struct port_buffer virtio_console: Add support for remoteproc serial drivers/char/virtio_console.c | 328 + include/linux/virtio_ids.h|1 + 2 files changed, 234 insertions(+), 95 deletions(-) -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH 3/3] virtio_console: Don't initialize buffers to zero
From: Sjur Brændeland Skip initializing the receive buffers. Signed-off-by: Sjur Brændeland --- drivers/char/virtio_console.c |1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index faedd2c..e7d8787 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1344,7 +1344,6 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) if (!buf) break; - memset(buf->buf, 0, PAGE_SIZE); spin_lock_irq(lock); ret = add_inbuf(vq, buf); if (ret < 0) { -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCHv5 2/3] virtio_console: Add support for remoteproc serial
From: Sjur Brændeland Add a simple serial connection driver called VIRTIO_ID_RPROC_SERIAL (11) for communicating with a remote processor in an asymmetric multi-processing configuration. This implementation reuses the existing virtio_console implementation, and adds support for DMA allocation of data buffers and disables use of tty console and the virtio control queue. Signed-off-by: Sjur Brændeland cc: Rusty Russell cc: Michael S. Tsirkin cc: Amit Shah cc: Ohad Ben-Cohen cc: Linus Walleij cc: Arnd Bergmann --- Changes since v4: - New baseline - Use name is_rproc_enabled - Renamed list and spin-lock used for pending deletion of dma buffers - Minor style fixes: indentation, removed brace drivers/char/virtio_console.c | 184 + include/linux/virtio_ids.h|1 + 2 files changed, 170 insertions(+), 15 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index f4f7b04..faedd2c 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -37,8 +37,12 @@ #include #include #include +#include +#include #include "../tty/hvc/hvc_console.h" +#define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC) + /* * This is a global struct for storing common data for all the devices * this driver handles. @@ -112,6 +116,15 @@ struct port_buffer { /* offset in the buf from which to consume data */ size_t offset; + /* DMA address of buffer */ + dma_addr_t dma; + + /* Device we got DMA memory from */ + struct device *dev; + + /* List of pending dma buffers to free */ + struct list_head list; + /* If sgpages == 0 then buf is used, else sg is used */ unsigned int sgpages; @@ -330,6 +343,11 @@ static bool is_console_port(struct port *port) return false; } +static bool is_rproc_serial(const struct virtio_device *vdev) +{ + return is_rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL; +} + static inline bool use_multiport(struct ports_device *portdev) { /* @@ -341,32 +359,84 @@ static inline bool use_multiport(struct ports_device *portdev) return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); } +static DEFINE_SPINLOCK(dma_bufs_lock); +static LIST_HEAD(pending_free_dma_bufs); + static void free_buf(struct port_buffer *buf) { int i; + unsigned long flags; - kfree(buf->buf); + if (!buf->dev) + kfree(buf->buf); - if (buf->sgpages) + if (buf->sgpages) { for (i = 0; i < buf->sgpages; i++) { struct page *page = sg_page(&buf->sg[i]); if (!page) break; put_page(page); } + return; + } + + if (buf->dev && is_rproc_enabled) { + + /* dma_free_coherent requires interrupts to be enabled. */ + if (irqs_disabled()) { + /* queue up dma-buffers to be freed later */ + spin_lock_irqsave(&dma_bufs_lock, flags); + list_add_tail(&buf->list, &pending_free_dma_bufs); + spin_unlock_irqrestore(&dma_bufs_lock, flags); + return; + } + dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma); + + /* Release device refcnt and allow it to be freed */ + might_sleep(); + put_device(buf->dev); + } kfree(buf); } +static void reclaim_dma_bufs(void) +{ + unsigned long flags; + struct port_buffer *buf, *tmp; + LIST_HEAD(tmp_list); + + WARN_ON(irqs_disabled()); + if (list_empty(&pending_free_dma_bufs)) + return; + + BUG_ON(!is_rproc_enabled); + + /* Create a copy of the pending_free_dma_bufs while holding the lock*/ + spin_lock_irqsave(&dma_bufs_lock, flags); + list_cut_position(&tmp_list, &pending_free_dma_bufs, + pending_free_dma_bufs.prev); + spin_unlock_irqrestore(&dma_bufs_lock, flags); + + /* Release the dma buffers, without irqs enabled */ + list_for_each_entry_safe(buf, tmp, &tmp_list, list) { + list_del(&buf->list); + free_buf(buf); + } +} + static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, int nrbufs) { struct port_buffer *buf; size_t alloc_size; + if (is_rproc_serial(vq->vdev) && !irqs_disabled()) + reclaim_dma_bufs(); + /* Allocate buffer and the scatter list */ alloc_size = sizeof(*buf) + sizeof(struct scatterlist) * nrbufs; - buf = kmalloc(alloc_size, GFP_ATOMIC); + buf = kzalloc(alloc_size, GFP_ATOMIC); if (!buf) goto fail; @@ -374,11 +444,30 @@ static struct port_bu
[PATCH 1/3] virtio_console:Merge struct buffer_token into struct port_buffer
From: Sjur Brændeland This merge reduces code size by unifying the approach for sending scatter-lists and regular buffers. Any type of write operation (splice, write, put_chars) will now allocate a port_buffer and send_buf() and free_buf() can always be used. Signed-off-by: Sjur Brændeland cc: Rusty Russell cc: Michael S. Tsirkin cc: Amit Shah cc: Linus Walleij cc: Masami Hiramatsu --- drivers/char/virtio_console.c | 141 ++--- 1 files changed, 62 insertions(+), 79 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8ab9c3d..f4f7b04 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -111,6 +111,11 @@ struct port_buffer { size_t len; /* offset in the buf from which to consume data */ size_t offset; + + /* If sgpages == 0 then buf is used, else sg is used */ + unsigned int sgpages; + + struct scatterlist sg[1]; }; /* @@ -338,23 +343,46 @@ static inline bool use_multiport(struct ports_device *portdev) static void free_buf(struct port_buffer *buf) { + int i; + kfree(buf->buf); + + if (buf->sgpages) + for (i = 0; i < buf->sgpages; i++) { + struct page *page = sg_page(&buf->sg[i]); + if (!page) + break; + put_page(page); + } + kfree(buf); } -static struct port_buffer *alloc_buf(size_t buf_size) +static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, +int nrbufs) { struct port_buffer *buf; + size_t alloc_size; - buf = kmalloc(sizeof(*buf), GFP_KERNEL); + /* Allocate buffer and the scatter list */ + alloc_size = sizeof(*buf) + sizeof(struct scatterlist) * nrbufs; + buf = kmalloc(alloc_size, GFP_ATOMIC); if (!buf) goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); + + buf->sgpages = nrbufs; + if (nrbufs > 0) + return buf; + + buf->buf = kmalloc(buf_size, GFP_ATOMIC); if (!buf->buf) goto free_buf; buf->len = 0; buf->offset = 0; buf->size = buf_size; + + /* Prepare scatter buffer for sending */ + sg_init_one(buf->sg, buf->buf, buf_size); return buf; free_buf: @@ -476,52 +504,25 @@ static ssize_t send_control_msg(struct port *port, unsigned int event, return 0; } -struct buffer_token { - union { - void *buf; - struct scatterlist *sg; - } u; - /* If sgpages == 0 then buf is used, else sg is used */ - unsigned int sgpages; -}; - -static void reclaim_sg_pages(struct scatterlist *sg, unsigned int nrpages) -{ - int i; - struct page *page; - - for (i = 0; i < nrpages; i++) { - page = sg_page(&sg[i]); - if (!page) - break; - put_page(page); - } - kfree(sg); -} /* Callers must take the port->outvq_lock */ static void reclaim_consumed_buffers(struct port *port) { - struct buffer_token *tok; + struct port_buffer *buf; unsigned int len; if (!port->portdev) { /* Device has been unplugged. vqs are already gone. */ return; } - while ((tok = virtqueue_get_buf(port->out_vq, &len))) { - if (tok->sgpages) - reclaim_sg_pages(tok->u.sg, tok->sgpages); - else - kfree(tok->u.buf); - kfree(tok); + while ((buf = virtqueue_get_buf(port->out_vq, &len))) { + free_buf(buf); port->outvq_full = false; } } -static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, - int nents, size_t in_count, - struct buffer_token *tok, bool nonblock) +static ssize_t send_buf(struct port *port, struct port_buffer *buf, int nents, + size_t in_count, bool nonblock) { struct virtqueue *out_vq; ssize_t ret; @@ -534,7 +535,7 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, reclaim_consumed_buffers(port); - ret = virtqueue_add_buf(out_vq, sg, nents, 0, tok, GFP_ATOMIC); + ret = virtqueue_add_buf(out_vq, buf->sg, nents, 0, buf, GFP_ATOMIC); /* Tell Host to go! */ virtqueue_kick(out_vq); @@ -559,8 +560,11 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, * we need to kmalloc a GFP_ATOMIC buffer each time the * console driver writes something out. */ - while (!virtqueue_get_buf(out_vq, &len)) + for (buf = virtqueue_get_buf(out_vq, &len); !buf; +buf = virtqueue_get_buf(out_vq, &len))
[PATCHv6 0/3] virtio_console: Add rproc_serial device
From: Sjur Brændeland I thought rebasing rproc_serial to linux-next was going to be trivial. But when starting the merge I realized that I had to refactor the the patches from Masami Hiramatsu. The splice support has the same issue as I faced, with different type of buffers in the out_vq. So I ended up refactoring the splice functionality. The code size got smaller so hopefully this a step in the right direction. This refactoring also make introduction of rproc_serial cleaner. As requested I also added a patch for not initializing buffers. I have tested the VIRTIO_CONSOLE device by looping large amount of data through character device and tty, with lockdep and slub-debug on. This looks stable for me. I've also done a simple test of splice. Thanks, Sjur cc: Rusty Russell cc: Michael S. Tsirkin cc: Amit Shah cc: Linus Walleij cc: Masami Hiramatsu Sjur Brændeland (3): virtio_console:Merge struct buffer_token into struct port_buffer virtio_console: Add support for remoteproc serial virtio_console: Don't initialize buffers to zero drivers/char/virtio_console.c | 318 + include/linux/virtio_ids.h|1 + 2 files changed, 228 insertions(+), 91 deletions(-) -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCHv4] virtio_console: Add support for remoteproc serial
From: Sjur Brændeland Add a simple serial connection driver called VIRTIO_ID_RPROC_SERIAL (11) for communicating with a remote processor in an asymmetric multi-processing configuration. This implementation reuses the existing virtio_console implementation, and adds support for DMA allocation of data buffers and disables use of tty console and the virtio control queue. Signed-off-by: Sjur Brændeland cc: Rusty Russell cc: Michael S. Tsirkin cc: Amit Shah cc: Ohad Ben-Cohen cc: Linus Walleij cc: Arnd Bergmann --- Changes since v3 are mostly related to freeing of dma-buffers: - Change port_fops_write() to use struct port_buffer when allocating memory. This is done in order to store the dma-address of the allocated buffers, so the correct dma-address can be passed to dma_free_coherent(). - Added pending_free_list for port_buf. dma_free_coherent() requires the irqs to be enabled, so if irqs are disabled we queue the buffer on the pending_free_list and free it later when irqs are enabled. - Remove #if around is_rproc_serial Thanks, Sjur drivers/char/virtio_console.c | 222 - include/linux/virtio_ids.h|1 + 2 files changed, 199 insertions(+), 24 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f54..3af9a5d 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -35,8 +35,12 @@ #include #include #include +#include +#include #include "../tty/hvc/hvc_console.h" +#define rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC) + /* * This is a global struct for storing common data for all the devices * this driver handles. @@ -109,6 +113,15 @@ struct port_buffer { size_t len; /* offset in the buf from which to consume data */ size_t offset; + + /* DMA address of buffer */ + dma_addr_t dma; + + /* Device we got DMA memory from */ + struct device *dev; + + /* List of pending dma buffers to free */ + struct list_head list; }; /* @@ -323,6 +336,11 @@ static bool is_console_port(struct port *port) return false; } +static bool is_rproc_serial(const struct virtio_device *vdev) +{ + return rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL; +} + static inline bool use_multiport(struct ports_device *portdev) { /* @@ -334,20 +352,99 @@ static inline bool use_multiport(struct ports_device *portdev) return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); } +static DEFINE_SPINLOCK(list_lock); +static LIST_HEAD(pending_free_list); + static void free_buf(struct port_buffer *buf) { - kfree(buf->buf); + unsigned long flags; + + if (!buf->dev) { + kfree(buf->buf); + goto freebuf; + } + + BUG_ON(!rproc_enabled); + + /* dma_free_coherent requires interrupts to be enabled */ + if (rproc_enabled && !irqs_disabled()) { + dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma); + + /* Release device refcnt and allow it to be freed */ + might_sleep(); + put_device(buf->dev); + goto freebuf; + } + + /* queue up dma-buffers to be freed later */ + spin_lock_irqsave(&list_lock, flags); + list_add_tail(&buf->list, &pending_free_list); + spin_unlock_irqrestore(&list_lock, flags); + return; + +freebuf: kfree(buf); } -static struct port_buffer *alloc_buf(size_t buf_size) +static void reclaim_dma_bufs(void) +{ + unsigned long flags; + struct port_buffer *buf, *tmp; + LIST_HEAD(tmp_list); + + WARN_ON(irqs_disabled()); + if (list_empty(&pending_free_list)) + return; + + BUG_ON(!rproc_enabled); + + /* Create a copy of the pending_free_list while holding the lock*/ + spin_lock_irqsave(&list_lock, flags); + list_cut_position(&tmp_list, &pending_free_list, + pending_free_list.prev); + spin_unlock_irqrestore(&list_lock, flags); + + /* Release the dma buffers, without irqs enabled */ + list_for_each_entry_safe(buf, tmp, &tmp_list, list) { + list_del(&buf->list); + free_buf(buf); + } +} + +static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size) { struct port_buffer *buf; + if (is_rproc_serial(vq->vdev) && !irqs_disabled()) + reclaim_dma_bufs(); + buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); + + if (is_rproc_serial(vq->vdev)) { + /* +* 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. +
[PATCHv3] virtio_console: Add support for remoteproc serial
From: Sjur Brændeland Add a simple serial connection driver called VIRTIO_ID_RPROC_SERIAL (11) for communicating with a remote processor in an asymmetric multi-processing configuration. This implementation reuses the existing virtio_console implementation, and adds support for DMA allocation of data buffers and disables use of tty console and the virtio control queue. This enables use of the exising virtio_console code in the remoteproc framework. Signed-off-by: Sjur Brændeland cc: Rusty Russell cc: Michael S. Tsirkin cc: Amit Shah cc: Ohad Ben-Cohen cc: Linus Walleij cc: virtualization@lists.linux-foundation.org --- Hi Amit, Changes since v2: Fixes for Rustys review comments. The only "unresolved" issue (unless I missed something) is the quirky handling of finding device grandparent when doing dma_alloc. [Rusty wrote:] >OK, I'll let Amit comment on the console changes, but some minor style >comments below. Amit, any chance that you might find time to review this? Note: This patch is based on v3.6 so this patch is will conflict with "virtio: console: fix error handling in init() function". Get back to me if you want me to rebase to another baseline. Thanks, Sjur drivers/char/virtio_console.c | 185 ++-- include/linux/virtio_ids.h|1 + 2 files changed, 158 insertions(+), 28 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f54..4f2f74e 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include "../tty/hvc/hvc_console.h" /* @@ -323,6 +325,55 @@ static bool is_console_port(struct port *port) return false; } +#if IS_ENABLED(CONFIG_REMOTEPROC) +static bool is_rproc_serial(const struct virtio_device *vdev) +{ + return vdev->id.device == VIRTIO_ID_RPROC_SERIAL; +} +#else +static bool is_rproc_serial(const struct virtio_device *vdev) +{ + return false; +} +#endif + +/* Allocate data buffer from DMA memory if requested */ +static void *alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag) +{ + if (is_rproc_serial(vdev)) { + dma_addr_t dma_addr; + struct device *dev = &vdev->dev; + /* +* 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. +* The code here would have been less quirky if +* DMA_MEMORY_INCLUDES_CHILDREN had been supported +* in dma-coherent.c +*/ + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + return dma_alloc_coherent(dev, size, &dma_addr, flag); + } + return kmalloc(size, flag); +} + +static void free_databuf(struct virtio_device *vdev, size_t size, void *vaddr) +{ + if (is_rproc_serial(vdev)) { + struct device *dev = &vdev->dev; + dma_addr_t dma_addr; + + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + dma_addr = virt_to_bus(vaddr); + dma_free_coherent(dev, size, vaddr, dma_addr); + return; + } + kfree(vaddr); +} + static inline bool use_multiport(struct ports_device *portdev) { /* @@ -334,22 +385,24 @@ static inline bool use_multiport(struct ports_device *portdev) return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); } -static void free_buf(struct port_buffer *buf) +static void free_buf(struct virtqueue *vq, struct port_buffer *buf, +size_t buf_size) { - kfree(buf->buf); + free_databuf(vq->vdev, buf_size, buf->buf); kfree(buf); } -static struct port_buffer *alloc_buf(size_t buf_size) +static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size) { struct port_buffer *buf; buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); + buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL); if (!buf->buf) goto free_buf; + memset(buf->buf, 0, buf_size); buf->len = 0; buf->offset = 0; buf->size = buf_size; @@ -414,7 +467,7 @@ static void discard_port_data(struct port *port) port->stats.bytes_discarded += buf->len - buf->offset; if (add_inbuf(port->in_vq, buf) < 0) { err++; - free_buf(buf); + free_buf(port->in_vq, buf, PAGE_SIZE); } port->inbuf = NULL; buf = get_inbuf(port); @@ -485,7 +538,7 @@ static void reclaim_consumed_buff
[PATCHv2] virtio_console: Add support for remoteproc serial
From: Sjur Brændeland Add a simple serial connection driver called VIRTIO_ID_RPROC_SERIAL (0xB) for communicating with a remote processor in an asymmetric multi-processing configuration. This implementation reuses the existing virtio_console implementation, and adds support for DMA allocation of data buffers and disables use of tty console and the virtio control queue. This enables use of the exising virtio_console code in the remoteproc framework. Signed-off-by: Sjur Brændeland cc: Michael S. Tsirkin cc: Amit Shah cc: Ohad Ben-Cohen cc: Linus Walleij --- Hi Rusty, Changes since v1: o Use proper macros IS_ENABLED(CONFIG_REMOTEPROC) o Fix bug at registration of rproc_serial driver o Always allocate PAGE_SIZE buffers for rproc_serial, and limit write to port_fops_write to use PAGE_SIZE. Regards, Sjur drivers/char/virtio_console.c | 160 ++--- include/linux/virtio_ids.h|1 + 2 files changed, 134 insertions(+), 27 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f54..395522a 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include "../tty/hvc/hvc_console.h" /* @@ -323,6 +325,52 @@ static bool is_console_port(struct port *port) return false; } +#if IS_ENABLED(CONFIG_REMOTEPROC) +static inline bool is_rproc_serial(struct virtio_device *vdev) +{ + return vdev->id.device == VIRTIO_ID_RPROC_SERIAL; +} +#else +static inline bool is_rproc_serial(struct virtio_device *vdev) +{ + return false; +} +#endif + +/* Allocate data buffer from DMA memory if requested */ +static inline void * +alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag) +{ + if (is_rproc_serial(vdev)) { + dma_addr_t dma; + struct device *dev = &vdev->dev; + /* +* Allocate DMA memory from ancestors. Finding the ancestor +* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not +* implemented. +*/ + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + return dma_alloc_coherent(dev, size, &dma, flag); + } + return kmalloc(size, flag); +} + +static inline void +free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr) +{ + + if (is_rproc_serial(vdev)) { + struct device *dev = &vdev->dev; + dma_addr_t dma_handle = virt_to_bus(cpu_addr); + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + dma_free_coherent(dev, size, cpu_addr, dma_handle); + return; + } + kfree(cpu_addr); +} + static inline bool use_multiport(struct ports_device *portdev) { /* @@ -334,20 +382,22 @@ static inline bool use_multiport(struct ports_device *portdev) return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); } -static void free_buf(struct port_buffer *buf) +static void +free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size) { - kfree(buf->buf); + free_databuf(vq->vdev, buf_size, buf->buf); kfree(buf); } -static struct port_buffer *alloc_buf(size_t buf_size) +static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size) { struct port_buffer *buf; buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); + buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL); + memset(buf->buf, 0, buf_size); if (!buf->buf) goto free_buf; buf->len = 0; @@ -414,7 +464,7 @@ static void discard_port_data(struct port *port) port->stats.bytes_discarded += buf->len - buf->offset; if (add_inbuf(port->in_vq, buf) < 0) { err++; - free_buf(buf); + free_buf(port->in_vq, buf, PAGE_SIZE); } port->inbuf = NULL; buf = get_inbuf(port); @@ -485,7 +535,7 @@ static void reclaim_consumed_buffers(struct port *port) return; } while ((buf = virtqueue_get_buf(port->out_vq, &len))) { - kfree(buf); + free_databuf(port->portdev->vdev, PAGE_SIZE, buf); port->outvq_full = false; } } @@ -672,6 +722,8 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, char *buf; ssize_t ret; bool nonblock; + struct virtio_device *vdev; + size_t buf_size; /* Userspace could be out to fool us */ if (!count) @@ -694,9 +746,16 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, if (!port->g
[PATCH] virtio_console: Add support for remoteproc serial
From: Sjur Brændeland Add a virtio remoteproc serial driver: VIRTIO_ID_RPROC_SERIAL (0xB) for communicating with a remote processor in an asymmetric multi-processing configuration. The virtio remoteproc serial driver reuses the existing virtio_console implementation, and adds support for DMA allocation of data buffers but disables support for tty console, mutiple ports, and the control queue. Signed-off-by: Sjur Brændeland --- cc: Rusty Russell cc: Michael S. Tsirkin cc: Amit Shah cc: Ohad Ben-Cohen cc: Linus Walleij cc: virtualization@lists.linux-foundation.org cc: linux-ker...@vger.kernel.org >Just one thing, should it depend on CONFIG_REMOTEPROC? And have >OMAP_REMOTEPROC depend on CONFIG_HAS_DMA (if it doesn't already). I have changed to use CONFIG_REMOTEPROC_MODULE now. I'll send a patch to Ohad adding an explicit dependency to HAS_DMA for remoteproc. >PS. I've reserved 11 for you in the latest virtio spec draft. Ok, I'll look into updating the spec. Thanks, Sjur drivers/char/virtio_console.c | 137 + include/linux/virtio_ids.h|1 + 2 files changed, 112 insertions(+), 26 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f54..7c697ca 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include "../tty/hvc/hvc_console.h" /* @@ -323,6 +325,52 @@ static bool is_console_port(struct port *port) return false; } +#ifdef CONFIG_REMOTEPROC_MODULE +static inline bool is_rproc_serial(struct virtio_device *vdev) +{ + return vdev->id.device == VIRTIO_ID_RPROC_SERIAL; +} +#else +static inline bool is_rproc_serial(struct virtio_device *vdev) +{ + return false; +} +#endif + +/* Allocate data buffer from DMA memory if requested */ +static inline void * +alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag) +{ + if (is_rproc_serial(vdev)) { + dma_addr_t dma; + struct device *dev = &vdev->dev; + /* +* Allocate DMA memory from ancestors. Finding the ancestor +* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not +* implemented. +*/ + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + return dma_alloc_coherent(dev, size, &dma, flag); + } + return kmalloc(size, flag); +} + +static inline void +free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr) +{ + + if (is_rproc_serial(vdev)) { + struct device *dev = &vdev->dev; + dma_addr_t dma_handle = virt_to_bus(cpu_addr); + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + dma_free_coherent(dev, size, cpu_addr, dma_handle); + return; + } + kfree(cpu_addr); +} + static inline bool use_multiport(struct ports_device *portdev) { /* @@ -334,20 +382,22 @@ static inline bool use_multiport(struct ports_device *portdev) return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); } -static void free_buf(struct port_buffer *buf) +static void +free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size) { - kfree(buf->buf); + free_databuf(vq->vdev, buf_size, buf->buf); kfree(buf); } -static struct port_buffer *alloc_buf(size_t buf_size) +static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size) { struct port_buffer *buf; buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); + buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL); + memset(buf->buf, 0, buf_size); if (!buf->buf) goto free_buf; buf->len = 0; @@ -414,7 +464,7 @@ static void discard_port_data(struct port *port) port->stats.bytes_discarded += buf->len - buf->offset; if (add_inbuf(port->in_vq, buf) < 0) { err++; - free_buf(buf); + free_buf(port->in_vq, buf, PAGE_SIZE); } port->inbuf = NULL; buf = get_inbuf(port); @@ -485,7 +535,7 @@ static void reclaim_consumed_buffers(struct port *port) return; } while ((buf = virtqueue_get_buf(port->out_vq, &len))) { - kfree(buf); + free_databuf(port->portdev->vdev, len, buf); port->outvq_full = false; } } @@ -672,6 +722,7 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, char *buf; ssize_t ret; bool nonblock; + struct virtio_device *vdev; /* Userspace could be out to fool u
[RFCv3] virtio_console: Add support for virtio remoteproc serial
From: Sjur Brændeland Add a virtio remoteproc serial driver: VIRTIO_ID_RPROC_SERIAL (0xB) for communicating with a remote processor in an asymmetric multi-processing configuration. The virtio remoteproc serial driver reuses the existing virtio_console implementation, and adds support for DMA allocation of data buffers but disables support for tty console, mutiple ports, and the control queue. Signed-off-by: Sjur Brændeland cc: Rusty Russell cc: Michael S. Tsirkin cc: Amit Shah cc: Ohad Ben-Cohen cc: Linus Walleij cc: virtualization@lists.linux-foundation.org cc: linux-ker...@vger.kernel.org --- Hi Rusty, ... >Sorry for the back and forth, I've been pondering MST's points. >If we make a new dma-multiport device (eg. ID 11), how ugly is the code? I don't think it's too bad. It's a few more code lines - as I have added a new virtio_driver definition and feature table. The rest is just replacing the check on feature bits with driver type. I no longer need to check on feature bits in the probe function, as the match on device type is done automatically by the driver framework. I actually like this new approach better. It solves the issues Michael has pointed out, and we don't have to think through side effects of weired combination of feature bits. >It would be a virtio console with DMA buffers and no console, just the >multiport stuff. This would have no impact on the current spec for >virtio console. Yes, and this way it will also be easier to explain what this new feature does. Regards, Sjur drivers/char/virtio_console.c | 133 + include/linux/virtio_ids.h|1 + 2 files changed, 109 insertions(+), 25 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f54..08593aa 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "../tty/hvc/hvc_console.h" /* @@ -323,6 +324,52 @@ static bool is_console_port(struct port *port) return false; } +#ifdef CONFIG_HAS_DMA +static inline bool is_rproc_serial(struct virtio_device *vdev) +{ + return vdev->id.device == VIRTIO_ID_RPROC_SERIAL; +} +#else +static inline bool is_rproc_serial(struct virtio_device *vdev) +{ + return false; +} +#endif + +/* Allocate data buffer from DMA memory if requested */ +static inline void * +alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag) +{ + if (is_rproc_serial(vdev)) { + dma_addr_t dma; + struct device *dev = &vdev->dev; + /* +* Allocate DMA memory from ancestors. Finding the ancestor +* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not +* implemented. +*/ + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + return dma_alloc_coherent(dev, size, &dma, flag); + } + return kzalloc(size, flag); +} + +static inline void +free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr) +{ + + if (is_rproc_serial(vdev)) { + struct device *dev = &vdev->dev; + dma_addr_t dma_handle = virt_to_bus(cpu_addr); + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + dma_free_coherent(dev, size, cpu_addr, dma_handle); + return; + } + kfree(cpu_addr); +} + static inline bool use_multiport(struct ports_device *portdev) { /* @@ -334,20 +381,21 @@ static inline bool use_multiport(struct ports_device *portdev) return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); } -static void free_buf(struct port_buffer *buf) +static void +free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size) { - kfree(buf->buf); + free_databuf(vq->vdev, buf_size, buf->buf); kfree(buf); } -static struct port_buffer *alloc_buf(size_t buf_size) +static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size) { struct port_buffer *buf; buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); + buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL); if (!buf->buf) goto free_buf; buf->len = 0; @@ -414,7 +462,7 @@ static void discard_port_data(struct port *port) port->stats.bytes_discarded += buf->len - buf->offset; if (add_inbuf(port->in_vq, buf) < 0) { err++; - free_buf(buf); + free_buf(port->in_vq, buf, PAGE_SIZE); } port->inbuf = NULL; buf = get_inbuf(port); @@ -485,7 +533,7 @@ static void reclaim_consumed_buffers(struct port *port)
[RFCv2 2/2] virtio_console: Add feature to disable console port
From: Sjur Brændeland Add the feature VIRTIO_CONSOLE_F_NO_HVC. With this bit set only port-devices are created. The console port and port control virtio-queues are not created. The console port is not suited for communicating to a remote processor because of it's blocking behavior. But the port-device supports efficient non-blocking IO to a remote processor. Signed-off-by: Sjur Brændeland cc: Rusty Russell cc: Michael S. Tsirkin cc: Amit Shah cc: Ohad Ben-Cohen cc: Linus Walleij cc: virtualization@lists.linux-foundation.org cc: linux-ker...@vger.kernel.org --- drivers/char/virtio_console.c |6 +- include/linux/virtio_console.h |1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 469c05f..7408c00 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1244,10 +1244,13 @@ static int add_port(struct ports_device *portdev, u32 id) goto free_device; } + /* Don't initialize the port_console if F_NO_HVC is set*/ + if (virtio_has_feature(port->portdev->vdev, VIRTIO_CONSOLE_F_NO_HVC)) + port->host_connected = true; /* * If we're not using multiport support, this has to be a console port */ - if (!use_multiport(port->portdev)) { + else if (!use_multiport(port->portdev)) { err = init_port_console(port); if (err) goto free_inbufs; @@ -1896,6 +1899,7 @@ static unsigned int features[] = { #if VIRTIO_CONSOLE_HAS_DMA VIRTIO_CONSOLE_F_DMA_MEM, #endif + VIRTIO_CONSOLE_F_NO_HVC, }; diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h index b27f7fa..a7c8974 100644 --- a/include/linux/virtio_console.h +++ b/include/linux/virtio_console.h @@ -39,6 +39,7 @@ #define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */ #define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */ #define VIRTIO_CONSOLE_F_DMA_MEM 2 /* Use DMA memory in vrings */ +#define VIRTIO_CONSOLE_F_NO_HVC 3 /* Disable use of HVC */ #define VIRTIO_CONSOLE_BAD_ID (~(u32)0) -- 1.7.9.5 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCHv2] virtio: Don't access device data after unregistration.
From: Sjur Brændeland Fix panic in virtio.c when CONFIG_DEBUG_SLAB is set. device_unregister() drops reference to device so put_device() could invoke release callback. In this case the release callback will free the device. Make sure we don't access device after unregister by fetching the device index before calling unregister. Signed-off-by: Sjur Brændeland cc: Guzman Lugo, Fernadndo cc: Michael S. Tsirkin cc: Rusty Russell cc: Ohad Ben-Cohen cc: virtualization@lists.linux-foundation.org cc: linux-ker...@vger.kernel.org --- drivers/virtio/virtio.c |9 - 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index c3b3f7f..faee112 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -225,8 +225,15 @@ EXPORT_SYMBOL_GPL(register_virtio_device); void unregister_virtio_device(struct virtio_device *dev) { + /* +* device_unregister() drops reference to device so put_device could +* invoke release callback. In case that callback will free the device, +* make sure we don't access device after this call. +*/ + + int index = dev->index; device_unregister(&dev->dev); - ida_simple_remove(&virtio_index_ida, dev->index); + ida_simple_remove(&virtio_index_ida, index); } EXPORT_SYMBOL_GPL(unregister_virtio_device); -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[RFCv2 1/2] virtio_console: Add support for DMA memory allocation
From: Sjur Brændeland Add feature VIRTIO_CONSOLE_F_DMA_MEM. If the architecture has DMA support and this feature bit is set, the virtio data buffers will be allocated from DMA memory. If the device requests the feature VIRTIO_CONSOLE_F_DMA_MEM, but the architecture don't support DMA the driver's probe function will fail. This is needed for using virtio_console from the remoteproc framework. Signed-off-by: Sjur Brændeland cc: Rusty Russell cc: Michael S. Tsirkin cc: Amit Shah cc: Ohad Ben-Cohen cc: Linus Walleij cc: virtualization@lists.linux-foundation.org cc: linux-ker...@vger.kernel.org --- drivers/char/virtio_console.c | 91 +--- include/linux/virtio_console.h |1 + 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f54..469c05f 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -35,8 +35,15 @@ #include #include #include +#include #include "../tty/hvc/hvc_console.h" +#ifdef CONFIG_HAS_DMA +#define VIRTIO_CONSOLE_HAS_DMA (1) +#else +#define VIRTIO_CONSOLE_HAS_DMA (0) +#endif + /* * This is a global struct for storing common data for all the devices * this driver handles. @@ -334,20 +341,56 @@ static inline bool use_multiport(struct ports_device *portdev) return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); } -static void free_buf(struct port_buffer *buf) +/* Allocate data buffer from DMA memory if requested */ +static inline void * +alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag) +{ + if (VIRTIO_CONSOLE_HAS_DMA && + virtio_has_feature(vdev, VIRTIO_CONSOLE_F_DMA_MEM)) { + struct device *dev = &vdev->dev; + dma_addr_t dma; + /* +* Allocate DMA memory from ancestors. Finding the ancestor +* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not +* implemented. +*/ + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + return dma_alloc_coherent(dev, size, &dma, flag); + } + return kzalloc(size, flag); +} + +static inline void +free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr) +{ + if (VIRTIO_CONSOLE_HAS_DMA && + virtio_has_feature(vdev, VIRTIO_CONSOLE_F_DMA_MEM)) { + struct device *dev = &vdev->dev; + dma_addr_t dma = virt_to_bus(cpu_addr); + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + dma_free_coherent(dev, size, cpu_addr, dma); + return; + } + kfree(cpu_addr); +} + +static void +free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size) { - kfree(buf->buf); + free_databuf(vq->vdev, buf_size, buf); kfree(buf); } -static struct port_buffer *alloc_buf(size_t buf_size) +static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size) { struct port_buffer *buf; buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); + buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL); if (!buf->buf) goto free_buf; buf->len = 0; @@ -414,7 +457,7 @@ static void discard_port_data(struct port *port) port->stats.bytes_discarded += buf->len - buf->offset; if (add_inbuf(port->in_vq, buf) < 0) { err++; - free_buf(buf); + free_buf(port->in_vq, buf, PAGE_SIZE); } port->inbuf = NULL; buf = get_inbuf(port); @@ -485,7 +528,7 @@ static void reclaim_consumed_buffers(struct port *port) return; } while ((buf = virtqueue_get_buf(port->out_vq, &len))) { - kfree(buf); + free_databuf(port->portdev->vdev, len, buf); port->outvq_full = false; } } @@ -672,6 +715,7 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, char *buf; ssize_t ret; bool nonblock; + struct virtio_device *vdev; /* Userspace could be out to fool us */ if (!count) @@ -694,9 +738,10 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, if (!port->guest_connected) return -ENODEV; + vdev = port->portdev->vdev; count = min((size_t)(32 * 1024), count); - buf = kmalloc(count, GFP_KERNEL); + buf = alloc_databuf(vdev, count, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -720,7 +765,8 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, goto out; free_buf:
[RFC 1/2] virtio_console: Add support for DMA memory allocation
From: Sjur Brændeland Add feature VIRTIO_CONSOLE_F_DMA_MEM. If the architecture has DMA support and this feature bit is set, the virtio data buffers will be allocated from DMA memory. This is needed for using virtio_console from the remoteproc framework. Signed-off-by: Sjur Brændeland cc: Rusty Russell cc: Michael S. Tsirkin cc: Ohad Ben-Cohen cc: Linus Walleij cc: virtualization@lists.linux-foundation.org --- drivers/char/virtio_console.c | 76 include/linux/virtio_console.h |1 + 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f54..6bfbd09 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "../tty/hvc/hvc_console.h" /* @@ -334,20 +335,60 @@ static inline bool use_multiport(struct ports_device *portdev) return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); } -static void free_buf(struct port_buffer *buf) +/* Allcoate data buffer from DMA memory if requested */ +static inline void * +alloc_databuf(struct virtio_device *vdev, size_t size, dma_addr_t *dma_handle, + gfp_t flag) { - kfree(buf->buf); +#ifdef CONFIG_HAS_DMA + if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_DMA_MEM)) { + struct device *dev = &vdev->dev; + /* +* Allocate DMA memory from ancestors. Finding the ancestor +* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not +* implemented. +*/ + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + return dma_alloc_coherent(dev, size, dma_handle, flag); + } +#endif + return kzalloc(size, flag); +} + +static inline void +free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr) +{ +#ifdef CONFIG_HAS_DMA + dma_addr_t dma_handle = virt_to_bus(cpu_addr); + if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_DMA_MEM)) { + struct device *dev = &vdev->dev; + + dev = dev->parent ? dev->parent : dev; + dev = dev->parent ? dev->parent : dev; + dma_free_coherent(dev, size, cpu_addr, dma_handle); + return; + } +#endif + kfree(cpu_addr); +} + +static void +free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size) +{ + free_databuf(vq->vdev, buf_size, buf); kfree(buf); } -static struct port_buffer *alloc_buf(size_t buf_size) +static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size) { struct port_buffer *buf; + dma_addr_t dma; buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); + buf->buf = alloc_databuf(vq->vdev, buf_size, &dma, GFP_KERNEL); if (!buf->buf) goto free_buf; buf->len = 0; @@ -414,7 +455,7 @@ static void discard_port_data(struct port *port) port->stats.bytes_discarded += buf->len - buf->offset; if (add_inbuf(port->in_vq, buf) < 0) { err++; - free_buf(buf); + free_buf(port->in_vq, buf, PAGE_SIZE); } port->inbuf = NULL; buf = get_inbuf(port); @@ -485,7 +526,7 @@ static void reclaim_consumed_buffers(struct port *port) return; } while ((buf = virtqueue_get_buf(port->out_vq, &len))) { - kfree(buf); + free_databuf(port->portdev->vdev, len, buf); port->outvq_full = false; } } @@ -672,6 +713,8 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, char *buf; ssize_t ret; bool nonblock; + struct virtio_device *vdev; + dma_addr_t dma; /* Userspace could be out to fool us */ if (!count) @@ -694,9 +737,10 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, if (!port->guest_connected) return -ENODEV; + vdev = port->portdev->vdev; count = min((size_t)(32 * 1024), count); - buf = kmalloc(count, GFP_KERNEL); + buf = alloc_databuf(vdev, count, &dma, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -720,7 +764,8 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, goto out; free_buf: - kfree(buf); + free_databuf(vdev, count, buf); + out: return ret; } @@ -1102,7 +1147,7 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) nr_added_bufs = 0; do { - buf = alloc_buf(PAGE_SIZE); + buf = alloc_buf(vq, PAGE_SIZE);
[RFC 2/2] virtio_console: Add feature to disable console port
From: Sjur Brændeland Add the feature VIRTIO_CONSOLE_F_NO_HVC. With this bit set only port-devices are created. The console port and port control virtio-queues are not created. The console port is not suited for communicating to a remote processor because of it's blocking behavior. But the port-device supports efficient non-blocking IO to a remote processor. Signed-off-by: Sjur Brændeland cc: Rusty Russell cc: Michael S. Tsirkin cc: virtualization@lists.linux-foundation.org cc: Ohad Ben-Cohen cc: Linus Walleij --- drivers/char/virtio_console.c |5 - include/linux/virtio_console.h |1 + 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 6bfbd09..81546e9 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1246,7 +1246,9 @@ static int add_port(struct ports_device *portdev, u32 id) /* * If we're not using multiport support, this has to be a console port */ - if (!use_multiport(port->portdev)) { + if (virtio_has_feature(port->portdev->vdev, VIRTIO_CONSOLE_F_NO_HVC)) + port->host_connected = true; + else if (!use_multiport(port->portdev)) { err = init_port_console(port); if (err) goto free_inbufs; @@ -1882,6 +1884,7 @@ static unsigned int features[] = { VIRTIO_CONSOLE_F_SIZE, VIRTIO_CONSOLE_F_MULTIPORT, VIRTIO_CONSOLE_F_DMA_MEM, + VIRTIO_CONSOLE_F_NO_HVC, }; #ifdef CONFIG_PM diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h index b27f7fa..a7c8974 100644 --- a/include/linux/virtio_console.h +++ b/include/linux/virtio_console.h @@ -39,6 +39,7 @@ #define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */ #define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */ #define VIRTIO_CONSOLE_F_DMA_MEM 2 /* Use DMA memory in vrings */ +#define VIRTIO_CONSOLE_F_NO_HVC 3 /* Disable use of HVC */ #define VIRTIO_CONSOLE_BAD_ID (~(u32)0) -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH] virtio: Don't access device data after unregistration.
From: Sjur Brændeland Fix panic in virtio.c when CONFIG_DEBUG_SLAB is set. Use device_del() and put_device() instead of device_unregister(), and access device data before calling put_device(). Signed-off-by: Sjur Brændeland cc: Guzman Lugo, Fernadndo cc: Michael S. Tsirkin cc: virtualization@lists.linux-foundation.org cc: Ohad Ben-Cohen --- drivers/virtio/virtio.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index c3b3f7f..71eacd1 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -225,8 +225,9 @@ EXPORT_SYMBOL_GPL(register_virtio_device); void unregister_virtio_device(struct virtio_device *dev) { - device_unregister(&dev->dev); + device_del(&dev->dev); ida_simple_remove(&virtio_index_ida, dev->index); + put_device(&dev->dev); } EXPORT_SYMBOL_GPL(unregister_virtio_device); -- 1.7.5.4 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization