Pull virtio updates from Michael Tsirkin: - new virtio CAN driver - support for LoongArch architecture in fw_cfg - support for firmware notifications in vdpa/octeon_ep - support for VFs in virtio core - fixes, cleanups all over the place, notably: - vhost: fix vhost_get_avail_idx for a non empty ring fixing an significant old perf regression - READ_ONCE() annotations mean virtio ring is now free of KCSAN warnings * tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (37 commits) can: virtio: Fix comment in UAPI header can: virtio: Add virtio CAN driver virtio: add num_vf callback to virtio_bus fw_cfg: Add support for LoongArch architecture vdpa/octeon_ep: fix IRQ-to-ring mapping in interrupt handler vdpa/octeon_ep: Add vDPA device event handling for firmware notifications vdpa/octeon_ep: Use 4 bytes for mailbox signature vdpa/octeon_ep: Fix PF->VF mailbox data address calculation vhost_task_create: kill unnecessary .exit_signal initialization vhost: remove unnecessary module_init/exit functions vdpa/mlx5: Use kvzalloc_flex() for MTT command memory vdpa_sim_net: switch to dynamic root device vdpa_sim_blk: switch to dynamic root device virtio-mem: Destroy mutex before freeing virtio_mem virtio-balloon: Destroy mutex before freeing virtio_balloon tools/virtio: fix build for kmalloc_obj API and missing stubs virtio_ring: Add READ_ONCE annotations for device-writable fields vduse: fix compat handling for VDUSE_IOTLB_GET_FD/VDUSE_VQ_GET_INFO tools/virtio: check mmap return value in vringh_test vhost/net: complete zerocopy ubufs only once ...
Unified · Split
| @@ -28326,6 +28326,15 @@ F: drivers/scsi/virtio_scsi.c · 28325 unmodified lines | ||
| 28326 | 28326 | F: include/uapi/linux/virtio_blk.h |
| 28327 | 28327 | F: include/uapi/linux/virtio_scsi.h |
| 28328 | 28328 | |
| 28329 | +VIRTIO CAN DRIVER | |
| 28330 | +M: "Harald Mommer" <harald.mommer@oss.qualcomm.com> | |
| 28331 | +M: "Matias Ezequiel Vara Larsen" <mvaralar@redhat.com> | |
| 28332 | +L: virtualization@lists.linux.dev | |
| 28333 | +L: linux-can@vger.kernel.org | |
| 28334 | +S: Maintained | |
| 28335 | +F: drivers/net/can/virtio_can.c | |
| 28336 | +F: include/uapi/linux/virtio_can.h | |
| 28337 | + | |
| 28329 | 28338 | VIRTIO CONSOLE DRIVER |
| 28330 | 28339 | M: Amit Shah <amit@kernel.org> |
| 28331 | 28340 | L: virtualization@lists.linux.dev |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <asm/barrier.h> |
| 8 | 8 | #include <linux/err.h> |
| 9 | 9 | #include <linux/hw_random.h> |
| 10 | +#include <linux/nospec.h> | |
| 10 | 11 | #include <linux/scatterlist.h> |
| 11 | 12 | #include <linux/spinlock.h> |
| 12 | 13 | #include <linux/virtio.h> |
| @@ -69,8 +70,26 @@ static void request_entropy(struct virtrng_info *vi) · 56 unmodified lines | ||
| 69 | 70 | static unsigned int copy_data(struct virtrng_info *vi, void *buf, |
| 70 | 71 | unsigned int size) |
| 71 | 72 | { |
| 72 | − size = min_t(unsigned int, size, vi->data_avail); | |
| 73 | − memcpy(buf, vi->data + vi->data_idx, size); | |
| 73 | + unsigned int idx, avail; | |
| 74 | + | |
| 75 | + /* | |
| 76 | + * vi->data_avail was set from the device-reported used.len and | |
| 77 | + * vi->data_idx was advanced by previous copy_data() calls. A | |
| 78 | + * malicious or buggy virtio-rng backend can drive either past | |
| 79 | + * sizeof(vi->data). Clamp at point of use and harden the index | |
| 80 | + * with array_index_nospec() so the memcpy() below cannot be | |
| 81 | + * steered into adjacent slab memory, including under | |
| 82 | + * speculation. | |
| 83 | + */ | |
| 84 | + avail = min_t(unsigned int, vi->data_avail, sizeof(vi->data)); | |
| 85 | + if (vi->data_idx >= avail) { | |
| 86 | + vi->data_avail = 0; | |
| 87 | + request_entropy(vi); | |
| 88 | + return 0; | |
| 89 | + } | |
| 90 | + size = min_t(unsigned int, size, avail - vi->data_idx); | |
| 91 | + idx = array_index_nospec(vi->data_idx, sizeof(vi->data)); | |
| 92 | + memcpy(buf, vi->data + idx, size); | |
| 74 | 93 | vi->data_idx += size; |
| 75 | 94 | vi->data_avail -= size; |
| 76 | 95 | if (vi->data_avail == 0) |
| @@ -1771,32 +1771,40 @@ static void config_intr(struct virtio_device *vdev) · 1770 unmodified lines | ||
| 1771 | 1771 | schedule_work(&portdev->config_work); |
| 1772 | 1772 | } |
| 1773 | 1773 | |
| 1774 | −static void config_work_handler(struct work_struct *work) | |
| 1774 | +static void update_size_from_config(struct ports_device *portdev) | |
| 1775 | 1775 | { |
| 1776 | − struct ports_device *portdev; | |
| 1776 | + struct virtio_device *vdev; | |
| 1777 | + struct port *port; | |
| 1778 | + u16 rows, cols; | |
| 1777 | 1779 | |
| 1778 | − portdev = container_of(work, struct ports_device, config_work); | |
| 1779 | − if (!use_multiport(portdev)) { | |
| 1780 | − struct virtio_device *vdev; | |
| 1781 | − struct port *port; | |
| 1782 | − u16 rows, cols; | |
| 1780 | + vdev = portdev->vdev; | |
| 1783 | 1781 | |
| 1784 | − vdev = portdev->vdev; | |
| 1785 | − virtio_cread(vdev, struct virtio_console_config, cols, &cols); | |
| 1786 | − virtio_cread(vdev, struct virtio_console_config, rows, &rows); | |
| 1782 | + /* | |
| 1783 | + * We'll use this way of resizing only for legacy support. | |
| 1784 | + * For multiport devices, use control messages to indicate | |
| 1785 | + * console size changes so that it can be done per-port. | |
| 1786 | + * | |
| 1787 | + * Don't test F_SIZE at all if we're rproc: not a valid feature. | |
| 1788 | + */ | |
| 1789 | + if (is_rproc_serial(vdev) || | |
| 1790 | + use_multiport(portdev) || | |
| 1791 | + !virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) | |
| 1792 | + return; | |
| 1787 | 1793 | |
| 1788 | − port = find_port_by_id(portdev, 0); | |
| 1789 | − set_console_size(port, rows, cols); | |
| 1794 | + virtio_cread(vdev, struct virtio_console_config, cols, &cols); | |
| 1795 | + virtio_cread(vdev, struct virtio_console_config, rows, &rows); | |
| 1790 | 1796 | |
| 1791 | − /* | |
| 1792 | − * We'll use this way of resizing only for legacy | |
| 1793 | − * support. For newer userspace | |
| 1794 | − * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages | |
| 1795 | − * to indicate console size changes so that it can be | |
| 1796 | − * done per-port. | |
| 1797 | − */ | |
| 1798 | − resize_console(port); | |
| 1799 | − } | |
| 1797 | + port = find_port_by_id(portdev, 0); | |
| 1798 | + set_console_size(port, rows, cols); | |
| 1799 | + resize_console(port); | |
| 1800 | +} | |
| 1801 | + | |
| 1802 | +static void config_work_handler(struct work_struct *work) | |
| 1803 | +{ | |
| 1804 | + struct ports_device *portdev; | |
| 1805 | + | |
| 1806 | + portdev = container_of(work, struct ports_device, config_work); | |
| 1807 | + update_size_from_config(portdev); | |
| 1800 | 1808 | } |
| 1801 | 1809 | |
| 1802 | 1810 | static int init_vqs(struct ports_device *portdev) |
| @@ -2052,6 +2060,8 @@ static int virtcons_probe(struct virtio_device *vdev) · 249 unmodified lines | ||
| 2052 | 2060 | __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, |
| 2053 | 2061 | VIRTIO_CONSOLE_DEVICE_READY, 1); |
| 2054 | 2062 | |
| 2063 | + update_size_from_config(portdev); | |
| 2064 | + | |
| 2055 | 2065 | return 0; |
| 2056 | 2066 | |
| 2057 | 2067 | free_chrdev: |
| @@ -124,7 +124,7 @@ config RASPBERRYPI_FIRMWARE · 123 unmodified lines | ||
| 124 | 124 | |
| 125 | 125 | config FW_CFG_SYSFS |
| 126 | 126 | tristate "QEMU fw_cfg device support in sysfs" |
| 127 | − depends on SYSFS && (ARM || ARM64 || PARISC || PPC_PMAC || RISCV || SPARC || X86) | |
| 127 | + depends on SYSFS && (ARM || ARM64 || LOONGARCH || PARISC || PPC_PMAC || RISCV || SPARC || X86) | |
| 128 | 128 | depends on HAS_IOPORT_MAP |
| 129 | 129 | default n |
| 130 | 130 | help |
| @@ -211,7 +211,7 @@ static void fw_cfg_io_cleanup(void) · 210 unmodified lines | ||
| 211 | 211 | |
| 212 | 212 | /* arch-specific ctrl & data register offsets are not available in ACPI, DT */ |
| 213 | 213 | #if !(defined(FW_CFG_CTRL_OFF) && defined(FW_CFG_DATA_OFF)) |
| 214 | −# if (defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_RISCV)) | |
| 214 | +# if (defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_LOONGARCH) || defined(CONFIG_RISCV)) | |
| 215 | 215 | # define FW_CFG_CTRL_OFF 0x08 |
| 216 | 216 | # define FW_CFG_DATA_OFF 0x00 |
| 217 | 217 | # define FW_CFG_DMA_OFF 0x10 |
| @@ -226,6 +226,18 @@ config CAN_TI_HECC · 225 unmodified lines | ||
| 226 | 226 | Driver for TI HECC (High End CAN Controller) module found on many |
| 227 | 227 | TI devices. The device specifications are available from www.ti.com |
| 228 | 228 | |
| 229 | +config CAN_VIRTIO_CAN | |
| 230 | + depends on VIRTIO | |
| 231 | + tristate "Virtio CAN device support" | |
| 232 | + default n | |
| 233 | + help | |
| 234 | + Say Y here if you want to support for Virtio CAN. | |
| 235 | + | |
| 236 | + To compile this driver as a module, choose M here: the | |
| 237 | + module will be called virtio-can. | |
| 238 | + | |
| 239 | + If unsure, say N. | |
| 240 | + | |
| 229 | 241 | config CAN_XILINXCAN |
| 230 | 242 | tristate "Xilinx CAN" |
| 231 | 243 | depends on ARCH_ZYNQ || ARM64 || MICROBLAZE || COMPILE_TEST |
| @@ -33,6 +33,7 @@ obj-$(CONFIG_CAN_PEAK_PCIEFD) += peak_canfd/ · 32 unmodified lines | ||
| 33 | 33 | obj-$(CONFIG_CAN_SJA1000) += sja1000/ |
| 34 | 34 | obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o |
| 35 | 35 | obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o |
| 36 | +obj-$(CONFIG_CAN_VIRTIO_CAN) += virtio_can.o | |
| 36 | 37 | obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o |
| 37 | 38 | |
| 38 | 39 | subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG |
| @@ -0,0 +1,1022 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +/* | |
| 3 | + * CAN bus driver for the Virtio CAN controller | |
| 4 | + * | |
| 5 | + * Copyright (C) 2021-2023 OpenSynergy GmbH | |
| 6 | + * Copyright Red Hat, Inc. 2025 | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#include <linux/atomic.h> | |
| 10 | +#include <linux/idr.h> | |
| 11 | +#include <linux/interrupt.h> | |
| 12 | +#include <linux/io.h> | |
| 13 | +#include <linux/kernel.h> | |
| 14 | +#include <linux/module.h> | |
| 15 | +#include <linux/mutex.h> | |
| 16 | +#include <linux/netdevice.h> | |
| 17 | +#include <linux/stddef.h> | |
| 18 | +#include <linux/can/dev.h> | |
| 19 | +#include <linux/virtio.h> | |
| 20 | +#include <linux/virtio_ring.h> | |
| 21 | +#include <linux/virtio_can.h> | |
| 22 | + | |
| 23 | +/* CAN device queues */ | |
| 24 | +#define VIRTIO_CAN_QUEUE_TX 0 | |
| 25 | +#define VIRTIO_CAN_QUEUE_RX 1 | |
| 26 | +#define VIRTIO_CAN_QUEUE_CONTROL 2 | |
| 27 | +#define VIRTIO_CAN_QUEUE_COUNT 3 | |
| 28 | + | |
| 29 | +#define CAN_KNOWN_FLAGS \ | |
| 30 | + (VIRTIO_CAN_FLAGS_EXTENDED |\ | |
| 31 | + VIRTIO_CAN_FLAGS_FD |\ | |
| 32 | + VIRTIO_CAN_FLAGS_RTR) | |
| 33 | + | |
| 34 | +/* Max. number of in flight TX messages */ | |
| 35 | +#define VIRTIO_CAN_ECHO_SKB_MAX 128 | |
| 36 | + | |
| 37 | +struct virtio_can_tx { | |
| 38 | + unsigned int putidx; | |
| 39 | + struct virtio_can_tx_in tx_in; | |
| 40 | + /* Keep virtio_can_tx_out at the end of the structure due to flex array */ | |
| 41 | + struct virtio_can_tx_out tx_out; | |
| 42 | +}; | |
| 43 | + | |
| 44 | +struct virtio_can_control { | |
| 45 | + struct virtio_can_control_out cpkt_out; | |
| 46 | + struct virtio_can_control_in cpkt_in; | |
| 47 | +}; | |
| 48 | + | |
| 49 | +/* virtio_can private data structure */ | |
| 50 | +struct virtio_can_priv { | |
| 51 | + struct can_priv can; /* must be the first member */ | |
| 52 | + /* NAPI for RX messages */ | |
| 53 | + struct napi_struct napi; | |
| 54 | + /* NAPI for TX messages */ | |
| 55 | + struct napi_struct napi_tx; | |
| 56 | + /* The network device we're associated with */ | |
| 57 | + struct net_device *dev; | |
| 58 | + /* The virtio device we're associated with */ | |
| 59 | + struct virtio_device *vdev; | |
| 60 | + /* The virtqueues */ | |
| 61 | + struct virtqueue *vqs[VIRTIO_CAN_QUEUE_COUNT]; | |
| 62 | + /* Lock for TX operations */ | |
| 63 | + spinlock_t tx_lock; | |
| 64 | + /* Control queue lock */ | |
| 65 | + struct mutex ctrl_lock; | |
| 66 | + /* Wait for control queue processing without polling */ | |
| 67 | + struct completion ctrl_done; | |
| 68 | + /* Array of receive queue messages */ | |
| 69 | + struct virtio_can_rx *rpkt; | |
| 70 | + struct virtio_can_control can_ctr_msg; | |
| 71 | + /* Data to get and maintain the putidx for local TX echo */ | |
| 72 | + struct ida tx_putidx_ida; | |
| 73 | + /* In flight TX messages */ | |
| 74 | + atomic_t tx_inflight; | |
| 75 | + /* Packet length */ | |
| 76 | + int rpkt_len; | |
| 77 | + /* BusOff pending. Reset after successful indication to upper layer */ | |
| 78 | + bool busoff_pending; | |
| 79 | + /* Tracks whether NAPI instances are currently enabled */ | |
| 80 | + bool napi_active; | |
| 81 | +}; | |
| 82 | + | |
| 83 | +static void virtqueue_napi_schedule(struct napi_struct *napi, | |
| 84 | + struct virtqueue *vq) | |
| 85 | +{ | |
| 86 | + if (napi_schedule_prep(napi)) { | |
| 87 | + virtqueue_disable_cb(vq); | |
| 88 | + __napi_schedule(napi); | |
| 89 | + } | |
| 90 | +} | |
| 91 | + | |
| 92 | +static void virtqueue_napi_complete(struct napi_struct *napi, | |
| 93 | + struct virtqueue *vq, int processed) | |
| 94 | +{ | |
| 95 | + int opaque; | |
| 96 | + | |
| 97 | + opaque = virtqueue_enable_cb_prepare(vq); | |
| 98 | + if (napi_complete_done(napi, processed)) { | |
| 99 | + if (unlikely(virtqueue_poll(vq, opaque))) | |
| 100 | + virtqueue_napi_schedule(napi, vq); | |
| 101 | + } else { | |
| 102 | + virtqueue_disable_cb(vq); | |
| 103 | + } | |
| 104 | +} | |
| 105 | + | |
| 106 | +static void virtio_can_free_candev(struct net_device *ndev) | |
| 107 | +{ | |
| 108 | + struct virtio_can_priv *priv = netdev_priv(ndev); | |
| 109 | + | |
| 110 | + ida_destroy(&priv->tx_putidx_ida); | |
| 111 | + free_candev(ndev); | |
| 112 | +} | |
| 113 | + | |
| 114 | +static void virtio_can_napi_enable(struct virtio_can_priv *priv) | |
| 115 | +{ | |
| 116 | + if (!priv->napi_active) { | |
| 117 | + napi_enable(&priv->napi); | |
| 118 | + napi_enable(&priv->napi_tx); | |
| 119 | + priv->napi_active = true; | |
| 120 | + } | |
| 121 | +} | |
| 122 | + | |
| 123 | +static void virtio_can_napi_disable(struct virtio_can_priv *priv) | |
| 124 | +{ | |
| 125 | + if (priv->napi_active) { | |
| 126 | + napi_disable(&priv->napi_tx); | |
| 127 | + napi_disable(&priv->napi); | |
| 128 | + priv->napi_active = false; | |
| 129 | + } | |
| 130 | +} | |
| 131 | + | |
| 132 | +static int virtio_can_alloc_tx_idx(struct virtio_can_priv *priv) | |
| 133 | +{ | |
| 134 | + int tx_idx; | |
| 135 | + | |
| 136 | + tx_idx = ida_alloc_max(&priv->tx_putidx_ida, | |
| 137 | + priv->can.echo_skb_max - 1, GFP_ATOMIC); | |
| 138 | + if (tx_idx >= 0) | |
| 139 | + atomic_inc(&priv->tx_inflight); | |
| 140 | + | |
| 141 | + return tx_idx; | |
| 142 | +} | |
| 143 | + | |
| 144 | +static void virtio_can_free_tx_idx(struct virtio_can_priv *priv, | |
| 145 | + unsigned int idx) | |
| 146 | +{ | |
| 147 | + ida_free(&priv->tx_putidx_ida, idx); | |
| 148 | + atomic_dec(&priv->tx_inflight); | |
| 149 | +} | |
| 150 | + | |
| 151 | +/* Create a scatter-gather list representing our input buffer and put | |
| 152 | + * it in the queue. | |
| 153 | + * | |
| 154 | + * Callers should take appropriate locks. | |
| 155 | + */ | |
| 156 | +static int virtio_can_add_inbuf(struct virtqueue *vq, void *buf, | |
| 157 | + unsigned int size) | |
| 158 | +{ | |
| 159 | + struct scatterlist sg[1]; | |
| 160 | + int ret; | |
| 161 | + | |
| 162 | + sg_init_one(sg, buf, size); | |
| 163 | + | |
| 164 | + ret = virtqueue_add_inbuf(vq, sg, 1, buf, GFP_ATOMIC); | |
| 165 | + | |
| 166 | + return ret; | |
| 167 | +} | |
| 168 | + | |
| 169 | +/* Send a control message with message type either | |
| 170 | + * | |
| 171 | + * - VIRTIO_CAN_SET_CTRL_MODE_START or | |
| 172 | + * - VIRTIO_CAN_SET_CTRL_MODE_STOP. | |
| 173 | + * | |
| 174 | + */ | |
| 175 | +static u8 virtio_can_send_ctrl_msg(struct net_device *ndev, u16 msg_type) | |
| 176 | +{ | |
| 177 | + struct scatterlist sg_out, sg_in, *sgs[2] = { &sg_out, &sg_in }; | |
| 178 | + struct virtio_can_priv *priv = netdev_priv(ndev); | |
| 179 | + struct virtqueue *vq = priv->vqs[VIRTIO_CAN_QUEUE_CONTROL]; | |
| 180 | + struct device *dev = &priv->vdev->dev; | |
| 181 | + unsigned int len; | |
| 182 | + int err; | |
| 183 | + | |
| 184 | + if (!vq) | |
| 185 | + return VIRTIO_CAN_RESULT_NOT_OK; | |
| 186 | + | |
| 187 | + guard(mutex)(&priv->ctrl_lock); | |
| 188 | + | |
| 189 | + priv->can_ctr_msg.cpkt_out.msg_type = cpu_to_le16(msg_type); | |
| 190 | + sg_init_one(&sg_out, &priv->can_ctr_msg.cpkt_out, | |
| 191 | + sizeof(priv->can_ctr_msg.cpkt_out)); | |
| 192 | + sg_init_one(&sg_in, &priv->can_ctr_msg.cpkt_in, sizeof(priv->can_ctr_msg.cpkt_in)); | |
| 193 | + | |
| 194 | + reinit_completion(&priv->ctrl_done); | |
| 195 | + | |
| 196 | + err = virtqueue_add_sgs(vq, sgs, 1u, 1u, priv, GFP_ATOMIC); | |
| 197 | + if (err != 0) { | |
| 198 | + dev_err(dev, "%s(): virtqueue_add_sgs() failed\n", __func__); | |
| 199 | + return VIRTIO_CAN_RESULT_NOT_OK; | |
| 200 | + } | |
| 201 | + | |
| 202 | + if (!virtqueue_kick(vq)) { | |
| 203 | + dev_err(dev, "%s(): Kick failed\n", __func__); | |
| 204 | + return VIRTIO_CAN_RESULT_NOT_OK; | |
| 205 | + } | |
| 206 | + | |
| 207 | + while (!virtqueue_get_buf(vq, &len) && !virtqueue_is_broken(vq)) | |
| 208 | + wait_for_completion(&priv->ctrl_done); | |
| 209 | + | |
| 210 | + return priv->can_ctr_msg.cpkt_in.result; | |
| 211 | +} | |
| 212 | + | |
| 213 | +static int virtio_can_start(struct net_device *ndev) | |
| 214 | +{ | |
| 215 | + struct virtio_can_priv *priv = netdev_priv(ndev); | |
| 216 | + u8 result; | |
| 217 | + | |
| 218 | + result = virtio_can_send_ctrl_msg(ndev, VIRTIO_CAN_SET_CTRL_MODE_START); | |
| 219 | + if (result != VIRTIO_CAN_RESULT_OK) { | |
| 220 | + netdev_err(ndev, "CAN controller start failed\n"); | |
| 221 | + return -EIO; | |
| 222 | + } | |
| 223 | + | |
| 224 | + priv->busoff_pending = false; | |
| 225 | + priv->can.state = CAN_STATE_ERROR_ACTIVE; | |
| 226 | + | |
| 227 | + return 0; | |
| 228 | +} | |
| 229 | + | |
| 230 | +static int virtio_can_set_mode(struct net_device *dev, enum can_mode mode) | |
| 231 | +{ | |
| 232 | + int err; | |
| 233 | + | |
| 234 | + switch (mode) { | |
| 235 | + case CAN_MODE_START: | |
| 236 | + err = virtio_can_start(dev); | |
| 237 | + if (err) | |
| 238 | + return err; | |
| 239 | + netif_wake_queue(dev); | |
| 240 | + break; | |
| 241 | + default: | |
| 242 | + return -EOPNOTSUPP; | |
| 243 | + } | |
| 244 | + | |
| 245 | + return 0; | |
| 246 | +} | |
| 247 | + | |
| 248 | +static int virtio_can_open(struct net_device *ndev) | |
| 249 | +{ | |
| 250 | + struct virtio_can_priv *priv = netdev_priv(ndev); | |
| 251 | + int err; | |
| 252 | + | |
| 253 | + err = open_candev(ndev); | |
| 254 | + if (err) | |
| 255 | + return err; | |
| 256 | + | |
| 257 | + err = virtio_can_start(ndev); | |
| 258 | + if (err) { | |
| 259 | + close_candev(ndev); | |
| 260 | + return err; | |
| 261 | + } | |
| 262 | + | |
| 263 | + virtio_can_napi_enable(priv); | |
| 264 | + netif_start_queue(ndev); | |
| 265 | + | |
| 266 | + return 0; | |
| 267 | +} | |
| 268 | + | |
| 269 | +static int virtio_can_stop(struct net_device *ndev) | |
| 270 | +{ | |
| 271 | + struct virtio_can_priv *priv = netdev_priv(ndev); | |
| 272 | + struct device *dev = &priv->vdev->dev; | |
| 273 | + u8 result; | |
| 274 | + | |
| 275 | + result = virtio_can_send_ctrl_msg(ndev, VIRTIO_CAN_SET_CTRL_MODE_STOP); | |
| 276 | + if (result != VIRTIO_CAN_RESULT_OK) { | |
| 277 | + dev_err(dev, "CAN controller stop failed\n"); | |
| 278 | + return -EIO; | |
| 279 | + } | |
| 280 | + | |
| 281 | + priv->busoff_pending = false; | |
| 282 | + priv->can.state = CAN_STATE_STOPPED; | |
| 283 | + | |
| 284 | + /* Switch carrier off if device was connected to the bus */ | |
| 285 | + if (netif_carrier_ok(ndev)) | |
| 286 | + netif_carrier_off(ndev); | |
| 287 | + | |
| 288 | + return 0; | |
| 289 | +} | |
| 290 | + | |
| 291 | +static int virtio_can_close(struct net_device *dev) | |
| 292 | +{ | |
| 293 | + struct virtio_can_priv *priv = netdev_priv(dev); | |
| 294 | + | |
| 295 | + netif_stop_queue(dev); | |
| 296 | + /* Ignore stop error: ndo_stop must always complete cleanup regardless. | |
| 297 | + * virtio_can_stop() already logs the error if it fails. | |
| 298 | + */ | |
| 299 | + virtio_can_stop(dev); | |
| 300 | + virtio_can_napi_disable(priv); | |
| 301 | + close_candev(dev); | |
| 302 | + | |
| 303 | + return 0; | |
| 304 | +} | |
| 305 | + | |
| 306 | +static netdev_tx_t virtio_can_start_xmit(struct sk_buff *skb, | |
| 307 | + struct net_device *dev) | |
| 308 | +{ | |
| 309 | + struct scatterlist sg_out, sg_in, *sgs[2] = { &sg_out, &sg_in }; | |
| 310 | + const unsigned int hdr_size = sizeof(struct virtio_can_tx_out); | |
| 311 | + struct canfd_frame *cf = (struct canfd_frame *)skb->data; | |
| 312 | + struct virtio_can_priv *priv = netdev_priv(dev); | |
| 313 | + struct virtqueue *vq = priv->vqs[VIRTIO_CAN_QUEUE_TX]; | |
| 314 | + netdev_tx_t xmit_ret = NETDEV_TX_OK; | |
| 315 | + struct virtio_can_tx *can_tx_msg; | |
| 316 | + u32 can_flags; | |
| 317 | + int putidx; | |
| 318 | + int err; | |
| 319 | + | |
| 320 | + if (can_dev_dropped_skb(dev, skb)) | |
| 321 | + goto kick; /* No way to return NET_XMIT_DROP here */ | |
| 322 | + | |
| 323 | + /* No local check for CAN_RTR_FLAG or FD frame against negotiated | |
| 324 | + * features. The device will reject those anyway if not supported. | |
| 325 | + */ | |
| 326 | + | |
| 327 | + can_tx_msg = kzalloc(sizeof(*can_tx_msg) + cf->len, GFP_ATOMIC); | |
| 328 | + if (!can_tx_msg) { | |
| 329 | + kfree_skb(skb); | |
| 330 | + dev->stats.tx_dropped++; | |
| 331 | + goto kick; /* No way to return NET_XMIT_DROP here */ | |
| 332 | + } | |
| 333 | + | |
| 334 | + can_tx_msg->tx_out.msg_type = cpu_to_le16(VIRTIO_CAN_TX); | |
| 335 | + can_tx_msg->tx_out.length = cpu_to_le16(cf->len); | |
| 336 | + can_flags = 0; | |
| 337 | + | |
| 338 | + if (cf->can_id & CAN_EFF_FLAG) { | |
| 339 | + can_flags |= VIRTIO_CAN_FLAGS_EXTENDED; | |
| 340 | + can_tx_msg->tx_out.can_id = cpu_to_le32(cf->can_id & CAN_EFF_MASK); | |
| 341 | + } else { | |
| 342 | + can_tx_msg->tx_out.can_id = cpu_to_le32(cf->can_id & CAN_SFF_MASK); | |
| 343 | + } | |
| 344 | + if (cf->can_id & CAN_RTR_FLAG) | |
| 345 | + can_flags |= VIRTIO_CAN_FLAGS_RTR; | |
| 346 | + else | |
| 347 | + memcpy(can_tx_msg->tx_out.sdu, cf->data, cf->len); | |
| 348 | + if (can_is_canfd_skb(skb)) | |
| 349 | + can_flags |= VIRTIO_CAN_FLAGS_FD; | |
| 350 | + | |
| 351 | + can_tx_msg->tx_out.flags = cpu_to_le32(can_flags); | |
| 352 | + | |
| 353 | + sg_init_one(&sg_out, &can_tx_msg->tx_out, hdr_size + cf->len); | |
| 354 | + sg_init_one(&sg_in, &can_tx_msg->tx_in, sizeof(can_tx_msg->tx_in)); | |
| 355 | + | |
| 356 | + putidx = virtio_can_alloc_tx_idx(priv); | |
| 357 | + | |
| 358 | + if (unlikely(putidx < 0)) { | |
| 359 | + /* -ENOMEM or -ENOSPC here. -ENOSPC should not be possible as | |
| 360 | + * tx_inflight >= can.echo_skb_max is checked in flow control | |
| 361 | + */ | |
| 362 | + WARN_ON_ONCE(putidx == -ENOSPC); | |
| 363 | + kfree(can_tx_msg); | |
| 364 | + kfree_skb(skb); | |
| 365 | + dev->stats.tx_dropped++; | |
| 366 | + goto kick; /* No way to return NET_XMIT_DROP here */ | |
| 367 | + } | |
| 368 | + | |
| 369 | + can_tx_msg->putidx = (unsigned int)putidx; | |
| 370 | + | |
| 371 | + /* Push loopback echo. Will be looped back on TX interrupt/TX NAPI */ | |
| 372 | + err = can_put_echo_skb(skb, dev, can_tx_msg->putidx, 0); | |
| 373 | + if (unlikely(err)) { | |
| 374 | + /* skb was already freed by can_put_echo_skb() on error */ | |
| 375 | + virtio_can_free_tx_idx(priv, can_tx_msg->putidx); | |
| 376 | + kfree(can_tx_msg); | |
| 377 | + dev->stats.tx_dropped++; | |
| 378 | + goto kick; | |
| 379 | + } | |
| 380 | + | |
| 381 | + /* Protect queue and list operations */ | |
| 382 | + scoped_guard(spinlock_irqsave, &priv->tx_lock) | |
| 383 | + err = virtqueue_add_sgs(vq, sgs, 1u, 1u, can_tx_msg, GFP_ATOMIC); | |
| 384 | + | |
| 385 | + if (unlikely(err)) { | |
| 386 | + /* | |
| 387 | + * can_put_echo_skb() already consumed skb via consume_skb(), | |
| 388 | + * so returning NETDEV_TX_BUSY would cause the stack to requeue | |
| 389 | + * a freed pointer. Drop the frame and return OK instead. | |
| 390 | + */ | |
| 391 | + can_free_echo_skb(dev, can_tx_msg->putidx, NULL); | |
| 392 | + virtio_can_free_tx_idx(priv, can_tx_msg->putidx); | |
| 393 | + netif_stop_queue(dev); | |
| 394 | + kfree(can_tx_msg); | |
| 395 | + dev->stats.tx_dropped++; | |
| 396 | + /* Expected never to be seen */ | |
| 397 | + netdev_warn(dev, "TX: Stop queue, err = %d\n", err); | |
| 398 | + goto kick; | |
| 399 | + } | |
| 400 | + | |
| 401 | + /* Normal flow control: stop queue when no transmission slots left */ | |
| 402 | + if (atomic_read(&priv->tx_inflight) >= priv->can.echo_skb_max || | |
| 403 | + vq->num_free == 0 || (vq->num_free < ARRAY_SIZE(sgs) && | |
| 404 | + !virtio_has_feature(vq->vdev, VIRTIO_RING_F_INDIRECT_DESC))) { | |
| 405 | + netif_stop_queue(dev); | |
| 406 | + netdev_dbg(dev, "TX: Normal stop queue\n"); | |
| 407 | + } | |
| 408 | + | |
| 409 | +kick: | |
| 410 | + if (netif_queue_stopped(dev) || !netdev_xmit_more()) { | |
| 411 | + scoped_guard(spinlock_irqsave, &priv->tx_lock) { | |
| 412 | + if (!virtqueue_kick(vq)) | |
| 413 | + netdev_err(dev, "%s(): Kick failed\n", __func__); | |
| 414 | + } | |
| 415 | + } | |
| 416 | + | |
| 417 | + return xmit_ret; | |
| 418 | +} | |
| 419 | + | |
| 420 | +static const struct net_device_ops virtio_can_netdev_ops = { | |
| 421 | + .ndo_open = virtio_can_open, | |
| 422 | + .ndo_stop = virtio_can_close, | |
| 423 | + .ndo_start_xmit = virtio_can_start_xmit, | |
| 424 | +}; | |
| 425 | + | |
| 426 | +static int register_virtio_can_dev(struct net_device *dev) | |
| 427 | +{ | |
| 428 | + dev->flags |= IFF_ECHO; /* we support local echo */ | |
| 429 | + dev->netdev_ops = &virtio_can_netdev_ops; | |
| 430 | + | |
| 431 | + return register_candev(dev); | |
| 432 | +} | |
| 433 | + | |
| 434 | +static int virtio_can_read_tx_queue(struct virtqueue *vq) | |
| 435 | +{ | |
| 436 | + struct virtio_can_priv *can_priv = vq->vdev->priv; | |
| 437 | + struct net_device *dev = can_priv->dev; | |
| 438 | + struct virtio_can_tx *can_tx_msg; | |
| 439 | + struct net_device_stats *stats; | |
| 440 | + unsigned int len; | |
| 441 | + u8 result; | |
| 442 | + | |
| 443 | + stats = &dev->stats; | |
| 444 | + | |
| 445 | + scoped_guard(spinlock_irqsave, &can_priv->tx_lock) | |
| 446 | + can_tx_msg = virtqueue_get_buf(vq, &len); | |
| 447 | + | |
| 448 | + if (!can_tx_msg) | |
| 449 | + return 0; | |
| 450 | + | |
| 451 | + if (unlikely(len < sizeof(struct virtio_can_tx_in))) { | |
| 452 | + netdev_err(dev, "TX ACK: Device sent no result code\n"); | |
| 453 | + result = VIRTIO_CAN_RESULT_NOT_OK; /* Keep things going */ | |
| 454 | + } else { | |
| 455 | + result = can_tx_msg->tx_in.result; | |
| 456 | + } | |
| 457 | + | |
| 458 | + if (can_priv->can.state < CAN_STATE_BUS_OFF) { | |
| 459 | + if (result != VIRTIO_CAN_RESULT_OK) { | |
| 460 | + struct can_frame *skb_cf; | |
| 461 | + struct sk_buff *skb = alloc_can_err_skb(dev, &skb_cf); | |
| 462 | + | |
| 463 | + if (skb) { | |
| 464 | + skb_cf->can_id |= CAN_ERR_CRTL; | |
| 465 | + skb_cf->data[1] |= CAN_ERR_CRTL_UNSPEC; | |
| 466 | + netif_rx(skb); | |
| 467 | + } | |
| 468 | + netdev_warn(dev, "TX ACK: Result = %u\n", result); | |
| 469 | + can_free_echo_skb(dev, can_tx_msg->putidx, NULL); | |
| 470 | + stats->tx_dropped++; | |
| 471 | + } else { | |
| 472 | + stats->tx_bytes += can_get_echo_skb(dev, can_tx_msg->putidx, | |
| 473 | + NULL); | |
| 474 | + stats->tx_packets++; | |
| 475 | + } | |
| 476 | + } else { | |
| 477 | + netdev_dbg(dev, "TX ACK: Controller inactive, drop echo\n"); | |
| 478 | + can_free_echo_skb(dev, can_tx_msg->putidx, NULL); | |
| 479 | + stats->tx_dropped++; | |
| 480 | + } | |
| 481 | + | |
| 482 | + virtio_can_free_tx_idx(can_priv, can_tx_msg->putidx); | |
| 483 | + | |
| 484 | + /* Flow control */ | |
| 485 | + if (netif_queue_stopped(dev)) { | |
| 486 | + netdev_dbg(dev, "TX ACK: Wake up stopped queue\n"); | |
| 487 | + netif_wake_queue(dev); | |
| 488 | + } | |
| 489 | + | |
| 490 | + kfree(can_tx_msg); | |
| 491 | + | |
| 492 | + return 1; /* Queue was not empty so there may be more data */ | |
| 493 | +} | |
| 494 | + | |
| 495 | +static int virtio_can_tx_poll(struct napi_struct *napi, int quota) | |
| 496 | +{ | |
| 497 | + struct net_device *dev = napi->dev; | |
| 498 | + struct virtio_can_priv *priv = netdev_priv(dev); | |
| 499 | + struct virtqueue *vq = priv->vqs[VIRTIO_CAN_QUEUE_TX]; | |
| 500 | + int work_done = 0; | |
| 501 | + | |
| 502 | + while (work_done < quota && virtio_can_read_tx_queue(vq) != 0) | |
| 503 | + work_done++; | |
| 504 | + | |
| 505 | + if (work_done < quota) | |
| 506 | + virtqueue_napi_complete(napi, vq, work_done); | |
| 507 | + | |
| 508 | + return work_done; | |
| 509 | +} | |
| 510 | + | |
| 511 | +static void virtio_can_tx_intr(struct virtqueue *vq) | |
| 512 | +{ | |
| 513 | + struct virtio_can_priv *can_priv = vq->vdev->priv; | |
| 514 | + | |
| 515 | + virtqueue_disable_cb(vq); | |
| 516 | + napi_schedule(&can_priv->napi_tx); | |
| 517 | +} | |
| 518 | + | |
| 519 | +/* This function is the NAPI RX poll function and NAPI guarantees that this | |
| 520 | + * function is not invoked simultaneously on multiple processors. | |
| 521 | + * Read a RX message from the used queue and sends it to the upper layer. | |
| 522 | + */ | |
| 523 | +static int virtio_can_read_rx_queue(struct virtqueue *vq) | |
| 524 | +{ | |
| 525 | + const unsigned int header_size = sizeof(struct virtio_can_rx); | |
| 526 | + struct virtio_can_priv *priv = vq->vdev->priv; | |
| 527 | + struct net_device *dev = priv->dev; | |
| 528 | + struct net_device_stats *stats; | |
| 529 | + struct virtio_can_rx *can_rx; | |
| 530 | + unsigned int transport_len; | |
| 531 | + struct canfd_frame *cf; | |
| 532 | + struct sk_buff *skb; | |
| 533 | + unsigned int len; | |
| 534 | + u32 can_flags; | |
| 535 | + u16 msg_type; | |
| 536 | + u32 can_id; | |
| 537 | + int ret; | |
| 538 | + | |
| 539 | + stats = &dev->stats; | |
| 540 | + | |
| 541 | + can_rx = virtqueue_get_buf(vq, &transport_len); | |
| 542 | + if (!can_rx) | |
| 543 | + return 0; /* No more data */ | |
| 544 | + | |
| 545 | + if (transport_len < header_size) { | |
| 546 | + netdev_warn(dev, "RX: Message too small\n"); | |
| 547 | + goto putback; | |
| 548 | + } | |
| 549 | + | |
| 550 | + if (priv->can.state >= CAN_STATE_ERROR_PASSIVE) { | |
| 551 | + netdev_dbg(dev, "%s(): Controller not active\n", __func__); | |
| 552 | + goto putback; | |
| 553 | + } | |
| 554 | + | |
| 555 | + msg_type = le16_to_cpu(can_rx->msg_type); | |
| 556 | + if (msg_type != VIRTIO_CAN_RX) { | |
| 557 | + netdev_warn(dev, "RX: Got unknown msg_type %04x\n", msg_type); | |
| 558 | + goto putback; | |
| 559 | + } | |
| 560 | + | |
| 561 | + len = le16_to_cpu(can_rx->length); | |
| 562 | + can_flags = le32_to_cpu(can_rx->flags); | |
| 563 | + can_id = le32_to_cpu(can_rx->can_id); | |
| 564 | + | |
| 565 | + if (can_flags & ~CAN_KNOWN_FLAGS) { | |
| 566 | + stats->rx_dropped++; | |
| 567 | + netdev_warn(dev, "RX: CAN Id 0x%08x: Invalid flags 0x%x\n", | |
| 568 | + can_id, can_flags); | |
| 569 | + goto putback; | |
| 570 | + } | |
| 571 | + | |
| 572 | + if (can_flags & VIRTIO_CAN_FLAGS_EXTENDED) { | |
| 573 | + can_id &= CAN_EFF_MASK; | |
| 574 | + can_id |= CAN_EFF_FLAG; | |
| 575 | + } else { | |
| 576 | + can_id &= CAN_SFF_MASK; | |
| 577 | + } | |
| 578 | + | |
| 579 | + if (can_flags & VIRTIO_CAN_FLAGS_RTR) { | |
| 580 | + if (!virtio_has_feature(vq->vdev, VIRTIO_CAN_F_RTR_FRAMES)) { | |
| 581 | + stats->rx_dropped++; | |
| 582 | + netdev_warn(dev, "RX: CAN Id 0x%08x: RTR not negotiated\n", | |
| 583 | + can_id); | |
| 584 | + goto putback; | |
| 585 | + } | |
| 586 | + if (can_flags & VIRTIO_CAN_FLAGS_FD) { | |
| 587 | + stats->rx_dropped++; | |
| 588 | + netdev_warn(dev, "RX: CAN Id 0x%08x: RTR with FD not possible\n", | |
| 589 | + can_id); | |
| 590 | + goto putback; | |
| 591 | + } | |
| 592 | + | |
| 593 | + if (len > 0xF) { | |
| 594 | + stats->rx_dropped++; | |
| 595 | + netdev_warn(dev, "RX: CAN Id 0x%08x: RTR with DLC > 0xF\n", | |
| 596 | + can_id); | |
| 597 | + goto putback; | |
| 598 | + } | |
| 599 | + | |
| 600 | + if (len > 0x8) | |
| 601 | + len = 0x8; | |
| 602 | + | |
| 603 | + can_id |= CAN_RTR_FLAG; | |
| 604 | + } | |
| 605 | + | |
| 606 | + if (transport_len < header_size + len) { | |
| 607 | + netdev_warn(dev, "RX: Message too small for payload\n"); | |
| 608 | + goto putback; | |
| 609 | + } | |
| 610 | + | |
| 611 | + if (can_flags & VIRTIO_CAN_FLAGS_FD) { | |
| 612 | + if (!virtio_has_feature(vq->vdev, VIRTIO_CAN_F_CAN_FD)) { | |
| 613 | + stats->rx_dropped++; | |
| 614 | + netdev_warn(dev, "RX: CAN Id 0x%08x: FD not negotiated\n", | |
| 615 | + can_id); | |
| 616 | + goto putback; | |
| 617 | + } | |
| 618 | + | |
| 619 | + if (len > CANFD_MAX_DLEN) | |
| 620 | + len = CANFD_MAX_DLEN; | |
| 621 | + | |
| 622 | + skb = alloc_canfd_skb(priv->dev, &cf); | |
| 623 | + } else { | |
| 624 | + if (!virtio_has_feature(vq->vdev, VIRTIO_CAN_F_CAN_CLASSIC)) { | |
| 625 | + stats->rx_dropped++; | |
| 626 | + netdev_warn(dev, "RX: CAN Id 0x%08x: classic not negotiated\n", | |
| 627 | + can_id); | |
| 628 | + goto putback; | |
| 629 | + } | |
| 630 | + | |
| 631 | + if (len > CAN_MAX_DLEN) | |
| 632 | + len = CAN_MAX_DLEN; | |
| 633 | + | |
| 634 | + skb = alloc_can_skb(priv->dev, (struct can_frame **)&cf); | |
| 635 | + } | |
| 636 | + if (!skb) { | |
| 637 | + stats->rx_dropped++; | |
| 638 | + netdev_warn(dev, "RX: No skb available\n"); | |
| 639 | + goto putback; | |
| 640 | + } | |
| 641 | + | |
| 642 | + cf->can_id = can_id; | |
| 643 | + cf->len = len; | |
| 644 | + if (!(can_flags & VIRTIO_CAN_FLAGS_RTR)) { | |
| 645 | + /* RTR frames have a DLC but no payload */ | |
| 646 | + memcpy(cf->data, can_rx->sdu, len); | |
| 647 | + } | |
| 648 | + | |
| 649 | + if (netif_receive_skb(skb) == NET_RX_SUCCESS) { | |
| 650 | + stats->rx_packets++; | |
| 651 | + if (!(can_flags & VIRTIO_CAN_FLAGS_RTR)) | |
| 652 | + stats->rx_bytes += len; | |
| 653 | + } | |
| 654 | + | |
| 655 | +putback: | |
| 656 | + /* Put processed RX buffer back into avail queue */ | |
| 657 | + ret = virtio_can_add_inbuf(vq, can_rx, | |
| 658 | + priv->rpkt_len); | |
| 659 | + if (!ret) | |
| 660 | + virtqueue_kick(vq); | |
| 661 | + return 1; /* Queue was not empty so there may be more data */ | |
| 662 | +} | |
| 663 | + | |
| 664 | +static int virtio_can_handle_busoff(struct net_device *dev) | |
| 665 | +{ | |
| 666 | + struct virtio_can_priv *priv = netdev_priv(dev); | |
| 667 | + struct can_frame *cf; | |
| 668 | + struct sk_buff *skb; | |
| 669 | + | |
| 670 | + if (!priv->busoff_pending) | |
| 671 | + return 0; | |
| 672 | + | |
| 673 | + if (priv->can.state < CAN_STATE_BUS_OFF) { | |
| 674 | + netdev_dbg(dev, "entered error bus off state\n"); | |
| 675 | + | |
| 676 | + /* bus-off state */ | |
| 677 | + priv->can.state = CAN_STATE_BUS_OFF; | |
| 678 | + priv->can.can_stats.bus_off++; | |
| 679 | + can_bus_off(dev); | |
| 680 | + } | |
| 681 | + | |
| 682 | + /* propagate the error condition to the CAN stack */ | |
| 683 | + skb = alloc_can_err_skb(dev, &cf); | |
| 684 | + if (unlikely(!skb)) | |
| 685 | + return 0; | |
| 686 | + | |
| 687 | + /* bus-off state */ | |
| 688 | + cf->can_id |= CAN_ERR_BUSOFF; | |
| 689 | + | |
| 690 | + /* Ensure that the BusOff indication does not get lost */ | |
| 691 | + if (netif_receive_skb(skb) == NET_RX_SUCCESS) | |
| 692 | + priv->busoff_pending = false; | |
| 693 | + | |
| 694 | + return 1; | |
| 695 | +} | |
| 696 | + | |
| 697 | +static int virtio_can_rx_poll(struct napi_struct *napi, int quota) | |
| 698 | +{ | |
| 699 | + struct net_device *dev = napi->dev; | |
| 700 | + struct virtio_can_priv *priv = netdev_priv(dev); | |
| 701 | + struct virtqueue *vq = priv->vqs[VIRTIO_CAN_QUEUE_RX]; | |
| 702 | + int work_done = 0; | |
| 703 | + | |
| 704 | + work_done += virtio_can_handle_busoff(dev); | |
| 705 | + | |
| 706 | + while (work_done < quota && virtio_can_read_rx_queue(vq) != 0) | |
| 707 | + work_done++; | |
| 708 | + | |
| 709 | + if (work_done < quota) | |
| 710 | + virtqueue_napi_complete(napi, vq, work_done); | |
| 711 | + | |
| 712 | + return work_done; | |
| 713 | +} | |
| 714 | + | |
| 715 | +static void virtio_can_rx_intr(struct virtqueue *vq) | |
| 716 | +{ | |
| 717 | + struct virtio_can_priv *can_priv = vq->vdev->priv; | |
| 718 | + | |
| 719 | + virtqueue_disable_cb(vq); | |
| 720 | + napi_schedule(&can_priv->napi); | |
| 721 | +} | |
| 722 | + | |
| 723 | +static void virtio_can_control_intr(struct virtqueue *vq) | |
| 724 | +{ | |
| 725 | + struct virtio_can_priv *can_priv = vq->vdev->priv; | |
| 726 | + | |
| 727 | + complete(&can_priv->ctrl_done); | |
| 728 | +} | |
| 729 | + | |
| 730 | +static void virtio_can_config_changed(struct virtio_device *vdev) | |
| 731 | +{ | |
| 732 | + struct virtio_can_priv *can_priv = vdev->priv; | |
| 733 | + u16 status; | |
| 734 | + | |
| 735 | + status = virtio_cread16(vdev, offsetof(struct virtio_can_config, | |
| 736 | + status)); | |
| 737 | + | |
| 738 | + if (!(status & VIRTIO_CAN_S_CTRL_BUSOFF)) | |
| 739 | + return; | |
| 740 | + | |
| 741 | + if (!can_priv->busoff_pending && | |
| 742 | + can_priv->can.state < CAN_STATE_BUS_OFF) { | |
| 743 | + can_priv->busoff_pending = true; | |
| 744 | + napi_schedule(&can_priv->napi); | |
| 745 | + } | |
| 746 | +} | |
| 747 | + | |
| 748 | +static void virtio_can_populate_rx_vq(struct virtio_device *vdev) | |
| 749 | +{ | |
| 750 | + struct virtio_can_priv *priv = vdev->priv; | |
| 751 | + struct virtqueue *vq = priv->vqs[VIRTIO_CAN_QUEUE_RX]; | |
| 752 | + unsigned int buf_size = priv->rpkt_len; | |
| 753 | + int num_elements = vq->num_free; | |
| 754 | + u8 *buf = (u8 *)priv->rpkt; | |
| 755 | + unsigned int idx; | |
| 756 | + int ret = 0; | |
| 757 | + | |
| 758 | + for (idx = 0; idx < num_elements; idx++) { | |
| 759 | + ret = virtio_can_add_inbuf(vq, buf, buf_size); | |
| 760 | + if (ret < 0) { | |
| 761 | + dev_dbg(&vdev->dev, "rpkt fill: ret=%d, idx=%u, size=%u\n", | |
| 762 | + ret, idx, buf_size); | |
| 763 | + break; | |
| 764 | + } | |
| 765 | + buf += buf_size; | |
| 766 | + } | |
| 767 | + | |
| 768 | + if (idx > 0) | |
| 769 | + virtqueue_kick(vq); | |
| 770 | + | |
| 771 | + dev_dbg(&vdev->dev, "%u rpkt added\n", idx); | |
| 772 | +} | |
| 773 | + | |
| 774 | +static int virtio_can_find_vqs(struct virtio_can_priv *priv) | |
| 775 | +{ | |
| 776 | + struct virtqueue_info vqs_info[] = { | |
| 777 | + { "can-tx", virtio_can_tx_intr }, | |
| 778 | + { "can-rx", virtio_can_rx_intr }, | |
| 779 | + { "can-state-ctrl", virtio_can_control_intr }, | |
| 780 | + }; | |
| 781 | + | |
| 782 | + /* Find the queues. */ | |
| 783 | + return virtio_find_vqs(priv->vdev, VIRTIO_CAN_QUEUE_COUNT, priv->vqs, | |
| 784 | + vqs_info, NULL); | |
| 785 | +} | |
| 786 | + | |
| 787 | +/* Function must not be called before virtio_can_find_vqs() has been run */ | |
| 788 | +static void virtio_can_del_vq(struct virtio_device *vdev) | |
| 789 | +{ | |
| 790 | + struct virtio_can_priv *priv = vdev->priv; | |
| 791 | + struct virtqueue *vq = priv->vqs[VIRTIO_CAN_QUEUE_TX]; | |
| 792 | + struct virtio_can_tx *can_tx_msg; | |
| 793 | + int q; | |
| 794 | + | |
| 795 | + if (!vq) | |
| 796 | + return; | |
| 797 | + | |
| 798 | + /* Reset the device */ | |
| 799 | + virtio_reset_device(vdev); | |
| 800 | + | |
| 801 | + /* From here we have dead silence from the device side so no locks | |
| 802 | + * are needed to protect against device side events. | |
| 803 | + */ | |
| 804 | + | |
| 805 | + /* Free pending TX buffers which were allocated in virtio_can_start_xmit() */ | |
| 806 | + while ((can_tx_msg = virtqueue_detach_unused_buf(vq))) { | |
| 807 | + can_free_echo_skb(priv->dev, can_tx_msg->putidx, NULL); | |
| 808 | + virtio_can_free_tx_idx(priv, can_tx_msg->putidx); | |
| 809 | + kfree(can_tx_msg); | |
| 810 | + } | |
| 811 | + | |
| 812 | + /* RX and control queue buffers are managed elsewhere, just detach */ | |
| 813 | + for (q = VIRTIO_CAN_QUEUE_RX; q < VIRTIO_CAN_QUEUE_COUNT; q++) | |
| 814 | + while (virtqueue_detach_unused_buf(priv->vqs[q])) | |
| 815 | + ; | |
| 816 | + | |
| 817 | + if (vdev->config->del_vqs) | |
| 818 | + vdev->config->del_vqs(vdev); | |
| 819 | + | |
| 820 | + memset(priv->vqs, 0, sizeof(priv->vqs)); | |
| 821 | +} | |
| 822 | + | |
| 823 | +static void virtio_can_remove(struct virtio_device *vdev) | |
| 824 | +{ | |
| 825 | + struct virtio_can_priv *priv = vdev->priv; | |
| 826 | + struct net_device *dev = priv->dev; | |
| 827 | + | |
| 828 | + unregister_candev(dev); | |
| 829 | + | |
| 830 | + virtio_can_del_vq(vdev); | |
| 831 | + | |
| 832 | + virtio_can_free_candev(dev); | |
| 833 | +} | |
| 834 | + | |
| 835 | +static int virtio_can_validate(struct virtio_device *vdev) | |
| 836 | +{ | |
| 837 | + /* CAN needs always access to the config space. | |
| 838 | + * Check that the driver can access the config space | |
| 839 | + */ | |
| 840 | + if (!vdev->config->get) { | |
| 841 | + dev_err(&vdev->dev, "%s failure: config access disabled\n", | |
| 842 | + __func__); | |
| 843 | + return -EINVAL; | |
| 844 | + } | |
| 845 | + | |
| 846 | + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { | |
| 847 | + dev_err(&vdev->dev, | |
| 848 | + "device does not comply with spec version 1.x\n"); | |
| 849 | + return -EINVAL; | |
| 850 | + } | |
| 851 | + | |
| 852 | + return 0; | |
| 853 | +} | |
| 854 | + | |
| 855 | +static int virtio_can_probe(struct virtio_device *vdev) | |
| 856 | +{ | |
| 857 | + struct virtio_can_priv *priv; | |
| 858 | + struct net_device *dev; | |
| 859 | + size_t size; | |
| 860 | + int err; | |
| 861 | + | |
| 862 | + dev = alloc_candev(sizeof(struct virtio_can_priv), | |
| 863 | + VIRTIO_CAN_ECHO_SKB_MAX); | |
| 864 | + if (!dev) | |
| 865 | + return -ENOMEM; | |
| 866 | + | |
| 867 | + priv = netdev_priv(dev); | |
| 868 | + | |
| 869 | + ida_init(&priv->tx_putidx_ida); | |
| 870 | + | |
| 871 | + netif_napi_add(dev, &priv->napi, virtio_can_rx_poll); | |
| 872 | + netif_napi_add(dev, &priv->napi_tx, virtio_can_tx_poll); | |
| 873 | + | |
| 874 | + SET_NETDEV_DEV(dev, &vdev->dev); | |
| 875 | + | |
| 876 | + priv->dev = dev; | |
| 877 | + priv->vdev = vdev; | |
| 878 | + vdev->priv = priv; | |
| 879 | + | |
| 880 | + priv->can.do_set_mode = virtio_can_set_mode; | |
| 881 | + priv->can.bittiming.bitrate = CAN_BITRATE_UNKNOWN; | |
| 882 | + /* Set Virtio CAN supported operations */ | |
| 883 | + priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING; | |
| 884 | + if (virtio_has_feature(vdev, VIRTIO_CAN_F_CAN_FD)) { | |
| 885 | + priv->can.fd.data_bittiming.bitrate = CAN_BITRATE_UNKNOWN; | |
| 886 | + err = can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD); | |
| 887 | + if (err != 0) | |
| 888 | + goto on_failure; | |
| 889 | + } | |
| 890 | + | |
| 891 | + /* Initialize virtqueues */ | |
| 892 | + err = virtio_can_find_vqs(priv); | |
| 893 | + if (err != 0) | |
| 894 | + goto on_failure; | |
| 895 | + | |
| 896 | + spin_lock_init(&priv->tx_lock); | |
| 897 | + mutex_init(&priv->ctrl_lock); | |
| 898 | + | |
| 899 | + init_completion(&priv->ctrl_done); | |
| 900 | + | |
| 901 | + priv->rpkt_len = sizeof(struct virtio_can_rx); | |
| 902 | + | |
| 903 | + if (virtio_has_feature(vdev, VIRTIO_CAN_F_CAN_FD)) | |
| 904 | + priv->rpkt_len += CANFD_MAX_DLEN; | |
| 905 | + else | |
| 906 | + priv->rpkt_len += CAN_MAX_DLEN; | |
| 907 | + | |
| 908 | + size = priv->rpkt_len * priv->vqs[VIRTIO_CAN_QUEUE_RX]->num_free; | |
| 909 | + priv->rpkt = devm_kzalloc(&vdev->dev, size, GFP_KERNEL); | |
| 910 | + if (!priv->rpkt) { | |
| 911 | + virtio_can_del_vq(vdev); | |
| 912 | + err = -ENOMEM; | |
| 913 | + goto on_failure; | |
| 914 | + } | |
| 915 | + virtio_can_populate_rx_vq(vdev); | |
| 916 | + | |
| 917 | + err = register_virtio_can_dev(dev); | |
| 918 | + if (err) { | |
| 919 | + virtio_can_del_vq(vdev); | |
| 920 | + goto on_failure; | |
| 921 | + } | |
| 922 | + | |
| 923 | + return 0; | |
| 924 | + | |
| 925 | +on_failure: | |
| 926 | + virtio_can_free_candev(dev); | |
| 927 | + return err; | |
| 928 | +} | |
| 929 | + | |
| 930 | +static int __maybe_unused virtio_can_freeze(struct virtio_device *vdev) | |
| 931 | +{ | |
| 932 | + struct virtio_can_priv *priv = vdev->priv; | |
| 933 | + struct net_device *ndev = priv->dev; | |
| 934 | + | |
| 935 | + if (netif_running(ndev)) { | |
| 936 | + /* virtio_can_close() calls netif_stop_queue(), virtio_can_stop(), | |
| 937 | + * napi_disable() and close_candev(). Call it directly (not via | |
| 938 | + * dev_close()) to preserve IFF_UP so that netif_running() returns | |
| 939 | + * true in virtio_can_restore() and the device is brought back up. | |
| 940 | + */ | |
| 941 | + virtio_can_close(ndev); | |
| 942 | + netif_device_detach(ndev); | |
| 943 | + } | |
| 944 | + | |
| 945 | + priv->can.state = CAN_STATE_SLEEPING; | |
| 946 | + | |
| 947 | + virtio_can_del_vq(vdev); | |
| 948 | + | |
| 949 | + return 0; | |
| 950 | +} | |
| 951 | + | |
| 952 | +static int __maybe_unused virtio_can_restore(struct virtio_device *vdev) | |
| 953 | +{ | |
| 954 | + struct virtio_can_priv *priv = vdev->priv; | |
| 955 | + struct net_device *ndev = priv->dev; | |
| 956 | + size_t size; | |
| 957 | + int err; | |
| 958 | + | |
| 959 | + err = virtio_can_find_vqs(priv); | |
| 960 | + if (err != 0) | |
| 961 | + return err; | |
| 962 | + | |
| 963 | + size = priv->rpkt_len * priv->vqs[VIRTIO_CAN_QUEUE_RX]->num_free; | |
| 964 | + priv->rpkt = devm_krealloc(&vdev->dev, priv->rpkt, size, GFP_KERNEL | __GFP_ZERO); | |
| 965 | + if (!priv->rpkt) { | |
| 966 | + virtio_can_del_vq(vdev); | |
| 967 | + return -ENOMEM; | |
| 968 | + } | |
| 969 | + virtio_can_populate_rx_vq(vdev); | |
| 970 | + | |
| 971 | + if (netif_running(ndev)) { | |
| 972 | + /* virtio_can_open() calls open_candev(), virtio_can_start(), | |
| 973 | + * napi_enable() and netif_start_queue(). Call it directly (not | |
| 974 | + * via dev_open()) since IFF_UP is still set from before freeze. | |
| 975 | + */ | |
| 976 | + err = virtio_can_open(ndev); | |
| 977 | + if (err) { | |
| 978 | + virtio_can_del_vq(vdev); | |
| 979 | + return err; | |
| 980 | + } | |
| 981 | + netif_device_attach(ndev); | |
| 982 | + } else { | |
| 983 | + priv->can.state = CAN_STATE_STOPPED; | |
| 984 | + } | |
| 985 | + | |
| 986 | + return 0; | |
| 987 | +} | |
| 988 | + | |
| 989 | +static struct virtio_device_id virtio_can_id_table[] = { | |
| 990 | + { VIRTIO_ID_CAN, VIRTIO_DEV_ANY_ID }, | |
| 991 | + { 0 }, | |
| 992 | +}; | |
| 993 | + | |
| 994 | +static unsigned int features[] = { | |
| 995 | + VIRTIO_CAN_F_CAN_CLASSIC, | |
| 996 | + VIRTIO_CAN_F_CAN_FD, | |
| 997 | + VIRTIO_CAN_F_LATE_TX_ACK, | |
| 998 | + VIRTIO_CAN_F_RTR_FRAMES, | |
| 999 | +}; | |
| 1000 | + | |
| 1001 | +static struct virtio_driver virtio_can_driver = { | |
| 1002 | + .feature_table = features, | |
| 1003 | + .feature_table_size = ARRAY_SIZE(features), | |
| 1004 | + .driver.name = KBUILD_MODNAME, | |
| 1005 | + .driver.owner = THIS_MODULE, | |
| 1006 | + .id_table = virtio_can_id_table, | |
| 1007 | + .validate = virtio_can_validate, | |
| 1008 | + .probe = virtio_can_probe, | |
| 1009 | + .remove = virtio_can_remove, | |
| 1010 | + .config_changed = virtio_can_config_changed, | |
| 1011 | +#ifdef CONFIG_PM_SLEEP | |
| 1012 | + .freeze = virtio_can_freeze, | |
| 1013 | + .restore = virtio_can_restore, | |
| 1014 | +#endif | |
| 1015 | +}; | |
| 1016 | + | |
| 1017 | +module_virtio_driver(virtio_can_driver); | |
| 1018 | +MODULE_DEVICE_TABLE(virtio, virtio_can_id_table); | |
| 1019 | + | |
| 1020 | +MODULE_AUTHOR("OpenSynergy GmbH"); | |
| 1021 | +MODULE_LICENSE("GPL"); | |
| 1022 | +MODULE_DESCRIPTION("CAN bus driver for Virtio CAN controller"); | |
| @@ -734,15 +734,22 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, · 733 unmodified lines | ||
| 734 | 734 | ret = dev_set_name(&vdpa_dev->dev, "%s", name); |
| 735 | 735 | else |
| 736 | 736 | ret = dev_set_name(&vdpa_dev->dev, "vdpa%u", vdpa_dev->index); |
| 737 | + if (ret) { | |
| 738 | + IFCVF_ERR(pdev, "Failed to set device name"); | |
| 739 | + goto err; | |
| 740 | + } | |
| 737 | 741 | |
| 738 | 742 | ret = _vdpa_register_device(&adapter->vdpa, vf->nr_vring); |
| 739 | 743 | if (ret) { |
| 740 | − put_device(&adapter->vdpa.dev); | |
| 741 | 744 | IFCVF_ERR(pdev, "Failed to register to vDPA bus"); |
| 742 | − return ret; | |
| 745 | + goto err; | |
| 743 | 746 | } |
| 744 | 747 | |
| 745 | 748 | return 0; |
| 749 | + | |
| 750 | +err: | |
| 751 | + put_device(&adapter->vdpa.dev); | |
| 752 | + return ret; | |
| 746 | 753 | } |
| 747 | 754 | |
| 748 | 755 | static void ifcvf_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev) |
| @@ -221,11 +221,10 @@ static int create_direct_keys(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr * · 220 unmodified lines | ||
| 221 | 221 | |
| 222 | 222 | list_for_each_entry(dmr, &mr->head, list) { |
| 223 | 223 | struct mlx5_create_mkey_mem *cmd_mem; |
| 224 | − int mttlen, mttcount; | |
| 224 | + int mttcount; | |
| 225 | 225 | |
| 226 | − mttlen = roundup(MLX5_ST_SZ_BYTES(mtt) * dmr->nsg, MLX5_VDPA_MTT_ALIGN); | |
| 227 | − mttcount = mttlen / sizeof(cmd_mem->mtt[0]); | |
| 228 | − cmd_mem = kvcalloc(1, struct_size(cmd_mem, mtt, mttcount), GFP_KERNEL); | |
| 226 | + mttcount = ALIGN(dmr->nsg, MLX5_VDPA_MTT_ALIGN / sizeof(cmd_mem->mtt[0])); | |
| 227 | + cmd_mem = kvzalloc_flex(*cmd_mem, mtt, mttcount); | |
| 229 | 228 | if (!cmd_mem) { |
| 230 | 229 | err = -ENOMEM; |
| 231 | 230 | goto done; |
| @@ -30,8 +30,10 @@ · 29 unmodified lines | ||
| 30 | 30 | #define OCTEP_EPF_RINFO(x) (0x000209f0 | ((x) << 25)) |
| 31 | 31 | #define OCTEP_VF_MBOX_DATA(x) (0x00010210 | ((x) << 17)) |
| 32 | 32 | #define OCTEP_PF_MBOX_DATA(x) (0x00022000 | ((x) << 4)) |
| 33 | +#define OCTEP_VF_EVENT_STATE(x) (0x00010030 | ((x) << 17)) | |
| 34 | +#define OCTEP_VF_EVENT_REG(x) (0x00010060 | ((x) << 17)) | |
| 33 | 35 | #define OCTEP_VF_IN_CTRL(x) (0x00010000 | ((x) << 17)) |
| 34 | −#define OCTEP_VF_IN_CTRL_RPVF(val) (((val) >> 48) & 0xF) | |
| 36 | +#define OCTEP_VF_IN_CTRL_RPVF(val) (FIELD_GET(GENMASK_ULL(51, 48), val)) | |
| 35 | 37 | |
| 36 | 38 | #define OCTEP_FW_READY_SIGNATURE0 0xFEEDFEED |
| 37 | 39 | #define OCTEP_FW_READY_SIGNATURE1 0x3355ffaa |
| @@ -43,9 +45,26 @@ enum octep_vdpa_dev_status { · 5 unmodified lines | ||
| 43 | 45 | OCTEP_VDPA_DEV_STATUS_WAIT_FOR_BAR_INIT, |
| 44 | 46 | OCTEP_VDPA_DEV_STATUS_INIT, |
| 45 | 47 | OCTEP_VDPA_DEV_STATUS_READY, |
| 48 | + OCTEP_VDPA_DEV_STATUS_ADDED, | |
| 49 | + OCTEP_VDPA_DEV_STATUS_REMOVED, | |
| 46 | 50 | OCTEP_VDPA_DEV_STATUS_UNINIT |
| 47 | 51 | }; |
| 48 | 52 | |
| 53 | +enum octep_vdpa_dev_event_state { | |
| 54 | + OCTEP_VDPA_DEV_NO_EVENT, | |
| 55 | + OCTEP_VDPA_DEV_NEW_EVENT, | |
| 56 | + OCTEP_VDPA_DEV_EVENT_ACTIVE, | |
| 57 | + OCTEP_VDPA_DEV_EVENT_DONE, | |
| 58 | +}; | |
| 59 | + | |
| 60 | +enum octep_vdpa_dev_event { | |
| 61 | + OCTEP_VDPA_DEV_EVENT_NONE, | |
| 62 | + OCTEP_VDPA_DEV_EVENT_ACK, | |
| 63 | + OCTEP_VDPA_DEV_EVENT_NACK, | |
| 64 | + OCTEP_VDPA_DEV_ADD_EVENT, | |
| 65 | + OCTEP_VDPA_DEV_DEL_EVENT, | |
| 66 | +}; | |
| 67 | + | |
| 49 | 68 | struct octep_vring_info { |
| 50 | 69 | struct vdpa_callback cb; |
| 51 | 70 | void __iomem *notify_addr; |
| @@ -86,6 +105,7 @@ struct octep_hw { · 34 unmodified lines | ||
| 86 | 105 | u64 features; |
| 87 | 106 | u16 nr_vring; |
| 88 | 107 | u32 config_size; |
| 108 | + int requested_irqs; | |
| 89 | 109 | int nb_irqs; |
| 90 | 110 | int *irqs; |
| 91 | 111 | u8 dev_id; |
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | 2 | /* Copyright (C) 2024 Marvell. */ |
| 3 | 3 | |
| 4 | +#include <linux/bitfield.h> | |
| 4 | 5 | #include <linux/interrupt.h> |
| 5 | 6 | #include <linux/io-64-nonatomic-lo-hi.h> |
| 6 | 7 | #include <linux/module.h> |
| @@ -8,6 +9,7 @@ · 1 unmodified line | ||
| 8 | 9 | #include "octep_vdpa.h" |
| 9 | 10 | |
| 10 | 11 | #define OCTEP_VDPA_DRIVER_NAME "octep_vdpa" |
| 12 | +#define OCTEP_VDPA_NAME_BUFSIZE 16 | |
| 11 | 13 | |
| 12 | 14 | struct octep_pf { |
| 13 | 15 | u8 __iomem *base[PCI_STD_NUM_BARS]; |
| @@ -19,6 +21,11 @@ struct octep_pf { · 5 unmodified lines | ||
| 19 | 21 | u16 vf_devid; |
| 20 | 22 | }; |
| 21 | 23 | |
| 24 | +struct octep_vdpa_event_wk { | |
| 25 | + struct work_struct work; | |
| 26 | + void *ctxptr; | |
| 27 | +}; | |
| 28 | + | |
| 22 | 29 | struct octep_vdpa { |
| 23 | 30 | struct vdpa_device vdpa; |
| 24 | 31 | struct octep_hw *oct_hw; |
| @@ -33,6 +40,8 @@ struct octep_vdpa_mgmt_dev { · 8 unmodified lines | ||
| 33 | 40 | struct work_struct setup_task; |
| 34 | 41 | /* Device status */ |
| 35 | 42 | atomic_t status; |
| 43 | + struct octep_vdpa *oct_vdpa; | |
| 44 | + struct octep_vdpa_event_wk event_wk; | |
| 36 | 45 | }; |
| 37 | 46 | |
| 38 | 47 | static struct octep_hw *vdpa_to_octep_hw(struct vdpa_device *vdpa_dev) |
| @@ -44,10 +53,31 @@ static struct octep_hw *vdpa_to_octep_hw(struct vdpa_device *vdpa_dev) · 5 unmodified lines | ||
| 44 | 53 | return oct_vdpa->oct_hw; |
| 45 | 54 | } |
| 46 | 55 | |
| 56 | +static inline void octep_vdpa_dev_event_schedule(struct octep_hw *oct_hw) | |
| 57 | +{ | |
| 58 | + u8 __iomem *addr = oct_hw->base[OCTEP_HW_MBOX_BAR]; | |
| 59 | + struct octep_vdpa_mgmt_dev *mgmt_dev; | |
| 60 | + | |
| 61 | + mgmt_dev = container_of(oct_hw, struct octep_vdpa_mgmt_dev, oct_hw); | |
| 62 | + writeb(OCTEP_VDPA_DEV_EVENT_ACTIVE, addr + OCTEP_VF_EVENT_STATE(0)); | |
| 63 | + schedule_work(&mgmt_dev->event_wk.work); | |
| 64 | +} | |
| 65 | + | |
| 66 | +static irqreturn_t octep_vdpa_dev_event_handler(int irq, void *data) | |
| 67 | +{ | |
| 68 | + struct octep_hw *oct_hw = data; | |
| 69 | + | |
| 70 | + if (readb(oct_hw->base[OCTEP_HW_MBOX_BAR] + OCTEP_VF_EVENT_STATE(0)) == | |
| 71 | + OCTEP_VDPA_DEV_NEW_EVENT) | |
| 72 | + octep_vdpa_dev_event_schedule(oct_hw); | |
| 73 | + | |
| 74 | + return IRQ_HANDLED; | |
| 75 | +} | |
| 76 | + | |
| 47 | 77 | static irqreturn_t octep_vdpa_intr_handler(int irq, void *data) |
| 48 | 78 | { |
| 49 | 79 | struct octep_hw *oct_hw = data; |
| 50 | − int i; | |
| 80 | + int i, start_ring_idx = -1; | |
| 51 | 81 | |
| 52 | 82 | /* Each device has multiple interrupts (nb_irqs) shared among rings |
| 53 | 83 | * (nr_vring). Device interrupts are mapped to the rings in a |
| @@ -60,7 +90,16 @@ static irqreturn_t octep_vdpa_intr_handler(int irq, void *data) · 6 unmodified lines | ||
| 60 | 90 | * 7 -> 7, 15, 23, 31, 39, 47, 55, 63; |
| 61 | 91 | */ |
| 62 | 92 | |
| 63 | − for (i = irq - oct_hw->irqs[0]; i < oct_hw->nr_vring; i += oct_hw->nb_irqs) { | |
| 93 | + for (i = 0; i < oct_hw->nb_irqs; i++) { | |
| 94 | + if (oct_hw->irqs[i] == irq) { | |
| 95 | + start_ring_idx = i; | |
| 96 | + break; | |
| 97 | + } | |
| 98 | + } | |
| 99 | + if (start_ring_idx == -1) | |
| 100 | + return IRQ_NONE; | |
| 101 | + | |
| 102 | + for (i = start_ring_idx; i < oct_hw->nr_vring; i += oct_hw->nb_irqs) { | |
| 64 | 103 | if (ioread8(oct_hw->vqs[i].cb_notify_addr)) { |
| 65 | 104 | /* Acknowledge the per ring notification to the device */ |
| 66 | 105 | iowrite8(0, oct_hw->vqs[i].cb_notify_addr); |
| @@ -72,11 +111,14 @@ static irqreturn_t octep_vdpa_intr_handler(int irq, void *data) · 5 unmodified lines | ||
| 72 | 111 | } |
| 73 | 112 | |
| 74 | 113 | /* Check for config interrupt. Config uses the first interrupt */ |
| 75 | − if (unlikely(irq == oct_hw->irqs[0] && ioread8(oct_hw->isr))) { | |
| 76 | − iowrite8(0, oct_hw->isr); | |
| 114 | + if (unlikely(irq == oct_hw->irqs[0])) { | |
| 115 | + if (ioread8(oct_hw->isr)) { | |
| 116 | + iowrite8(0, oct_hw->isr); | |
| 77 | 117 | |
| 78 | − if (oct_hw->config_cb.callback) | |
| 79 | − oct_hw->config_cb.callback(oct_hw->config_cb.private); | |
| 118 | + if (oct_hw->config_cb.callback) | |
| 119 | + oct_hw->config_cb.callback(oct_hw->config_cb.private); | |
| 120 | + } | |
| 121 | + octep_vdpa_dev_event_handler(irq, data); | |
| 80 | 122 | } |
| 81 | 123 | |
| 82 | 124 | return IRQ_HANDLED; |
| @@ -100,33 +142,41 @@ static void octep_free_irqs(struct octep_hw *oct_hw) · 17 unmodified lines | ||
| 100 | 142 | pci_free_irq_vectors(pdev); |
| 101 | 143 | devm_kfree(&pdev->dev, oct_hw->irqs); |
| 102 | 144 | oct_hw->irqs = NULL; |
| 145 | + oct_hw->requested_irqs = 0; | |
| 103 | 146 | } |
| 104 | 147 | |
| 105 | −static int octep_request_irqs(struct octep_hw *oct_hw) | |
| 148 | +static int octep_request_irqs(struct octep_hw *oct_hw, irqreturn_t (*irq_handler)(int, void *), | |
| 149 | + int nb_irqs) | |
| 106 | 150 | { |
| 107 | 151 | struct pci_dev *pdev = oct_hw->pdev; |
| 108 | 152 | int ret, irq, idx; |
| 109 | 153 | |
| 110 | − oct_hw->irqs = devm_kcalloc(&pdev->dev, oct_hw->nb_irqs, sizeof(int), GFP_KERNEL); | |
| 154 | + if ((oct_hw->requested_irqs != nb_irqs) || (nb_irqs == 1)) | |
| 155 | + octep_free_irqs(oct_hw); | |
| 156 | + else | |
| 157 | + return 0; | |
| 158 | + | |
| 159 | + oct_hw->irqs = devm_kcalloc(&pdev->dev, nb_irqs, sizeof(int), GFP_KERNEL); | |
| 111 | 160 | if (!oct_hw->irqs) |
| 112 | 161 | return -ENOMEM; |
| 113 | 162 | |
| 114 | − ret = pci_alloc_irq_vectors(pdev, 1, oct_hw->nb_irqs, PCI_IRQ_MSIX); | |
| 163 | + ret = pci_alloc_irq_vectors(pdev, 1, nb_irqs, PCI_IRQ_MSIX); | |
| 115 | 164 | if (ret < 0) { |
| 116 | 165 | dev_err(&pdev->dev, "Failed to alloc msix vector"); |
| 117 | 166 | return ret; |
| 118 | 167 | } |
| 119 | 168 | |
| 120 | − for (idx = 0; idx < oct_hw->nb_irqs; idx++) { | |
| 169 | + for (idx = 0; idx < nb_irqs; idx++) { | |
| 121 | 170 | irq = pci_irq_vector(pdev, idx); |
| 122 | − ret = devm_request_irq(&pdev->dev, irq, octep_vdpa_intr_handler, 0, | |
| 123 | − dev_name(&pdev->dev), oct_hw); | |
| 171 | + ret = devm_request_irq(&pdev->dev, irq, irq_handler, 0, dev_name(&pdev->dev), | |
| 172 | + oct_hw); | |
| 124 | 173 | if (ret) { |
| 125 | 174 | dev_err(&pdev->dev, "Failed to register interrupt handler\n"); |
| 126 | 175 | goto free_irqs; |
| 127 | 176 | } |
| 128 | 177 | oct_hw->irqs[idx] = irq; |
| 129 | 178 | } |
| 179 | + oct_hw->requested_irqs = nb_irqs; | |
| 130 | 180 | |
| 131 | 181 | return 0; |
| 132 | 182 | |
| @@ -188,7 +238,7 @@ static void octep_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status) · 55 unmodified lines | ||
| 188 | 238 | |
| 189 | 239 | if ((status & VIRTIO_CONFIG_S_DRIVER_OK) && |
| 190 | 240 | !(status_old & VIRTIO_CONFIG_S_DRIVER_OK)) { |
| 191 | − if (octep_request_irqs(oct_hw)) | |
| 241 | + if (octep_request_irqs(oct_hw, octep_vdpa_intr_handler, oct_hw->nb_irqs)) | |
| 192 | 242 | status = status_old | VIRTIO_CONFIG_S_FAILED; |
| 193 | 243 | } |
| 194 | 244 | octep_hw_set_status(oct_hw, status); |
| @@ -211,8 +261,10 @@ static int octep_vdpa_reset(struct vdpa_device *vdpa_dev) · 16 unmodified lines | ||
| 211 | 261 | } |
| 212 | 262 | octep_hw_reset(oct_hw); |
| 213 | 263 | |
| 214 | − if (status & VIRTIO_CONFIG_S_DRIVER_OK) | |
| 264 | + if (status & VIRTIO_CONFIG_S_DRIVER_OK) { | |
| 215 | 265 | octep_free_irqs(oct_hw); |
| 266 | + octep_request_irqs(oct_hw, octep_vdpa_dev_event_handler, 1); | |
| 267 | + } | |
| 216 | 268 | |
| 217 | 269 | return 0; |
| 218 | 270 | } |
| @@ -477,7 +529,8 @@ static void octep_vdpa_remove_vf(struct pci_dev *pdev) · 258 unmodified lines | ||
| 477 | 529 | atomic_set(&mgmt_dev->status, OCTEP_VDPA_DEV_STATUS_UNINIT); |
| 478 | 530 | |
| 479 | 531 | cancel_work_sync(&mgmt_dev->setup_task); |
| 480 | − if (status == OCTEP_VDPA_DEV_STATUS_READY) | |
| 532 | + if ((status == OCTEP_VDPA_DEV_STATUS_READY) || (status == OCTEP_VDPA_DEV_STATUS_ADDED) || | |
| 533 | + (status == OCTEP_VDPA_DEV_STATUS_REMOVED)) | |
| 481 | 534 | vdpa_mgmtdev_unregister(&mgmt_dev->mdev); |
| 482 | 535 | |
| 483 | 536 | if (oct_hw->base[OCTEP_HW_CAPS_BAR]) |
| @@ -487,6 +540,7 @@ static void octep_vdpa_remove_vf(struct pci_dev *pdev) · 3 unmodified lines | ||
| 487 | 540 | octep_iounmap_region(pdev, oct_hw->base, OCTEP_HW_MBOX_BAR); |
| 488 | 541 | |
| 489 | 542 | octep_vdpa_vf_bar_shrink(pdev); |
| 543 | + octep_free_irqs(oct_hw); | |
| 490 | 544 | } |
| 491 | 545 | |
| 492 | 546 | static void octep_vdpa_remove(struct pci_dev *pdev) |
| @@ -520,6 +574,7 @@ static int octep_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, · 27 unmodified lines | ||
| 520 | 574 | oct_vdpa->vdpa.mdev = mdev; |
| 521 | 575 | oct_vdpa->oct_hw = oct_hw; |
| 522 | 576 | vdpa_dev = &oct_vdpa->vdpa; |
| 577 | + mgmt_dev->oct_vdpa = oct_vdpa; | |
| 523 | 578 | |
| 524 | 579 | device_features = oct_hw->features; |
| 525 | 580 | if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { |
| @@ -553,6 +608,7 @@ static int octep_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, · 27 unmodified lines | ||
| 553 | 608 | dev_err(&pdev->dev, "Failed to register to vDPA bus"); |
| 554 | 609 | goto vdpa_dev_put; |
| 555 | 610 | } |
| 611 | + atomic_set(&mgmt_dev->status, OCTEP_VDPA_DEV_STATUS_ADDED); | |
| 556 | 612 | return 0; |
| 557 | 613 | |
| 558 | 614 | vdpa_dev_put: |
| @@ -562,7 +618,9 @@ vdpa_dev_put: · 3 unmodified lines | ||
| 562 | 618 | |
| 563 | 619 | static void octep_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, struct vdpa_device *vdpa_dev) |
| 564 | 620 | { |
| 621 | + struct octep_vdpa_mgmt_dev *mgmt_dev = container_of(mdev, struct octep_vdpa_mgmt_dev, mdev); | |
| 565 | 622 | _vdpa_unregister_device(vdpa_dev); |
| 623 | + atomic_set(&mgmt_dev->status, OCTEP_VDPA_DEV_STATUS_REMOVED); | |
| 566 | 624 | } |
| 567 | 625 | |
| 568 | 626 | static const struct vdpa_mgmtdev_ops octep_vdpa_mgmt_dev_ops = { |
| @@ -572,10 +630,10 @@ static const struct vdpa_mgmtdev_ops octep_vdpa_mgmt_dev_ops = { · 3 unmodified lines | ||
| 572 | 630 | |
| 573 | 631 | static bool get_device_ready_status(u8 __iomem *addr) |
| 574 | 632 | { |
| 575 | − u64 signature = readq(addr + OCTEP_VF_MBOX_DATA(0)); | |
| 633 | + u32 signature = readl(addr + OCTEP_VF_MBOX_DATA(0)); | |
| 576 | 634 | |
| 577 | 635 | if (signature == OCTEP_DEV_READY_SIGNATURE) { |
| 578 | − writeq(0, addr + OCTEP_VF_MBOX_DATA(0)); | |
| 636 | + writel(0, addr + OCTEP_VF_MBOX_DATA(0)); | |
| 579 | 637 | return true; |
| 580 | 638 | } |
| 581 | 639 | |
| @@ -587,6 +645,36 @@ static struct virtio_device_id id_table[] = { · 5 unmodified lines | ||
| 587 | 645 | { 0 }, |
| 588 | 646 | }; |
| 589 | 647 | |
| 648 | +static void octep_event_work(struct work_struct *work) | |
| 649 | +{ | |
| 650 | + struct octep_vdpa_event_wk *wk = container_of(work, struct octep_vdpa_event_wk, work); | |
| 651 | + struct octep_vdpa_mgmt_dev *mgmt_dev = (struct octep_vdpa_mgmt_dev *)wk->ctxptr; | |
| 652 | + u8 __iomem *addr = mgmt_dev->oct_hw.base[OCTEP_HW_MBOX_BAR]; | |
| 653 | + u8 event = readb(addr + OCTEP_VF_EVENT_REG(0)); | |
| 654 | + struct vdpa_dev_set_config config = {0}; | |
| 655 | + char name[OCTEP_VDPA_NAME_BUFSIZE]; | |
| 656 | + int ret = 0; | |
| 657 | + | |
| 658 | + switch (event) { | |
| 659 | + case OCTEP_VDPA_DEV_ADD_EVENT: | |
| 660 | + if (atomic_read(&mgmt_dev->status) != OCTEP_VDPA_DEV_STATUS_ADDED) { | |
| 661 | + snprintf(name, sizeof(name), "%s-%x", "vdpa", mgmt_dev->pdev->devfn); | |
| 662 | + ret = octep_vdpa_dev_add(&mgmt_dev->mdev, name, &config); | |
| 663 | + } | |
| 664 | + break; | |
| 665 | + case OCTEP_VDPA_DEV_DEL_EVENT: | |
| 666 | + if (atomic_read(&mgmt_dev->status) == OCTEP_VDPA_DEV_STATUS_ADDED) | |
| 667 | + octep_vdpa_dev_del(&mgmt_dev->mdev, &mgmt_dev->oct_vdpa->vdpa); | |
| 668 | + break; | |
| 669 | + default: | |
| 670 | + break; | |
| 671 | + } | |
| 672 | + | |
| 673 | + event = ret ? OCTEP_VDPA_DEV_EVENT_NACK : OCTEP_VDPA_DEV_EVENT_ACK; | |
| 674 | + writeb(event, addr + OCTEP_VF_EVENT_REG(0)); | |
| 675 | + writeb(OCTEP_VDPA_DEV_EVENT_DONE, addr + OCTEP_VF_EVENT_STATE(0)); | |
| 676 | +} | |
| 677 | + | |
| 590 | 678 | static void octep_vdpa_setup_task(struct work_struct *work) |
| 591 | 679 | { |
| 592 | 680 | struct octep_vdpa_mgmt_dev *mgmt_dev = container_of(work, struct octep_vdpa_mgmt_dev, |
| @@ -652,6 +740,9 @@ static void octep_vdpa_setup_task(struct work_struct *work) · 59 unmodified lines | ||
| 652 | 740 | } |
| 653 | 741 | |
| 654 | 742 | atomic_set(&mgmt_dev->status, OCTEP_VDPA_DEV_STATUS_READY); |
| 743 | + INIT_WORK(&mgmt_dev->event_wk.work, octep_event_work); | |
| 744 | + mgmt_dev->event_wk.ctxptr = mgmt_dev; | |
| 745 | + octep_request_irqs(&mgmt_dev->oct_hw, octep_vdpa_dev_event_handler, 1); | |
| 655 | 746 | |
| 656 | 747 | return; |
| 657 | 748 | |
| @@ -722,6 +813,8 @@ static int octep_sriov_enable(struct pci_dev *pdev, int num_vfs) · 64 unmodified lines | ||
| 722 | 813 | bool done = false; |
| 723 | 814 | int index = 0; |
| 724 | 815 | int ret, i; |
| 816 | + u8 rpvf; | |
| 817 | + u64 val; | |
| 725 | 818 | |
| 726 | 819 | ret = pci_enable_sriov(pdev, num_vfs); |
| 727 | 820 | if (ret) |
| @@ -741,9 +834,11 @@ static int octep_sriov_enable(struct pci_dev *pdev, int num_vfs) · 13 unmodified lines | ||
| 741 | 834 | } |
| 742 | 835 | } |
| 743 | 836 | |
| 837 | + val = readq(addr + OCTEP_EPF_RINFO(0)); | |
| 838 | + rpvf = FIELD_GET(GENMASK_ULL(35, 32), val); | |
| 744 | 839 | if (done) { |
| 745 | 840 | for (i = 0; i < pf->enabled_vfs; i++) |
| 746 | − writeq(OCTEP_DEV_READY_SIGNATURE, addr + OCTEP_PF_MBOX_DATA(i)); | |
| 841 | + writel(OCTEP_DEV_READY_SIGNATURE, addr + OCTEP_PF_MBOX_DATA(i * rpvf)); | |
| 747 | 842 | } |
| 748 | 843 | |
| 749 | 844 | return num_vfs; |
| @@ -397,14 +397,7 @@ static void vdpasim_blk_free(struct vdpasim *vdpasim) · 396 unmodified lines | ||
| 397 | 397 | kvfree(blk->buffer); |
| 398 | 398 | } |
| 399 | 399 | |
| 400 | −static void vdpasim_blk_mgmtdev_release(struct device *dev) | |
| 401 | −{ | |
| 402 | −} | |
| 403 | − | |
| 404 | −static struct device vdpasim_blk_mgmtdev = { | |
| 405 | − .init_name = "vdpasim_blk", | |
| 406 | − .release = vdpasim_blk_mgmtdev_release, | |
| 407 | −}; | |
| 400 | +static struct device *vdpasim_blk_mgmtdev; | |
| 408 | 401 | |
| 409 | 402 | static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, |
| 410 | 403 | const struct vdpa_dev_set_config *config) |
| @@ -475,7 +468,6 @@ static struct virtio_device_id id_table[] = { · 64 unmodified lines | ||
| 475 | 468 | }; |
| 476 | 469 | |
| 477 | 470 | static struct vdpa_mgmt_dev mgmt_dev = { |
| 478 | − .device = &vdpasim_blk_mgmtdev, | |
| 479 | 471 | .id_table = id_table, |
| 480 | 472 | .ops = &vdpasim_blk_mgmtdev_ops, |
| 481 | 473 | }; |
| @@ -484,12 +476,11 @@ static int __init vdpasim_blk_init(void) · 2 unmodified lines | ||
| 484 | 476 | { |
| 485 | 477 | int ret; |
| 486 | 478 | |
| 487 | − ret = device_register(&vdpasim_blk_mgmtdev); | |
| 488 | − if (ret) { | |
| 489 | − put_device(&vdpasim_blk_mgmtdev); | |
| 490 | − return ret; | |
| 491 | − } | |
| 479 | + vdpasim_blk_mgmtdev = root_device_register("vdpasim_blk"); | |
| 480 | + if (IS_ERR(vdpasim_blk_mgmtdev)) | |
| 481 | + return PTR_ERR(vdpasim_blk_mgmtdev); | |
| 492 | 482 | |
| 483 | + mgmt_dev.device = vdpasim_blk_mgmtdev; | |
| 493 | 484 | ret = vdpa_mgmtdev_register(&mgmt_dev); |
| 494 | 485 | if (ret) |
| 495 | 486 | goto parent_err; |
| @@ -507,7 +498,8 @@ static int __init vdpasim_blk_init(void) · 11 unmodified lines | ||
| 507 | 498 | mgmt_dev_err: |
| 508 | 499 | vdpa_mgmtdev_unregister(&mgmt_dev); |
| 509 | 500 | parent_err: |
| 510 | − device_unregister(&vdpasim_blk_mgmtdev); | |
| 501 | + root_device_unregister(vdpasim_blk_mgmtdev); | |
| 502 | + | |
| 511 | 503 | return ret; |
| 512 | 504 | } |
| 513 | 505 | |
| @@ -515,7 +507,7 @@ static void __exit vdpasim_blk_exit(void) · 1 unmodified line | ||
| 515 | 507 | { |
| 516 | 508 | kvfree(shared_buffer); |
| 517 | 509 | vdpa_mgmtdev_unregister(&mgmt_dev); |
| 518 | − device_unregister(&vdpasim_blk_mgmtdev); | |
| 510 | + root_device_unregister(vdpasim_blk_mgmtdev); | |
| 519 | 511 | } |
| 520 | 512 | |
| 521 | 513 | module_init(vdpasim_blk_init) |
| @@ -453,14 +453,7 @@ static void vdpasim_net_free(struct vdpasim *vdpasim) · 452 unmodified lines | ||
| 453 | 453 | kvfree(net->buffer); |
| 454 | 454 | } |
| 455 | 455 | |
| 456 | −static void vdpasim_net_mgmtdev_release(struct device *dev) | |
| 457 | −{ | |
| 458 | −} | |
| 459 | − | |
| 460 | −static struct device vdpasim_net_mgmtdev = { | |
| 461 | − .init_name = "vdpasim_net", | |
| 462 | − .release = vdpasim_net_mgmtdev_release, | |
| 463 | −}; | |
| 456 | +static struct device *vdpasim_net_mgmtdev; | |
| 464 | 457 | |
| 465 | 458 | static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, |
| 466 | 459 | const struct vdpa_dev_set_config *config) |
| @@ -538,7 +531,6 @@ static struct virtio_device_id id_table[] = { · 71 unmodified lines | ||
| 538 | 531 | }; |
| 539 | 532 | |
| 540 | 533 | static struct vdpa_mgmt_dev mgmt_dev = { |
| 541 | − .device = &vdpasim_net_mgmtdev, | |
| 542 | 534 | .id_table = id_table, |
| 543 | 535 | .ops = &vdpasim_net_mgmtdev_ops, |
| 544 | 536 | .config_attr_mask = (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR | |
| @@ -552,26 +544,25 @@ static int __init vdpasim_net_init(void) · 7 unmodified lines | ||
| 552 | 544 | { |
| 553 | 545 | int ret; |
| 554 | 546 | |
| 555 | − ret = device_register(&vdpasim_net_mgmtdev); | |
| 556 | − if (ret) { | |
| 557 | − put_device(&vdpasim_net_mgmtdev); | |
| 558 | − return ret; | |
| 559 | − } | |
| 547 | + vdpasim_net_mgmtdev = root_device_register("vdpasim_net"); | |
| 548 | + if (IS_ERR(vdpasim_net_mgmtdev)) | |
| 549 | + return PTR_ERR(vdpasim_net_mgmtdev); | |
| 560 | 550 | |
| 551 | + mgmt_dev.device = vdpasim_net_mgmtdev; | |
| 561 | 552 | ret = vdpa_mgmtdev_register(&mgmt_dev); |
| 562 | 553 | if (ret) |
| 563 | 554 | goto parent_err; |
| 564 | 555 | return 0; |
| 565 | 556 | |
| 566 | 557 | parent_err: |
| 567 | − device_unregister(&vdpasim_net_mgmtdev); | |
| 558 | + root_device_unregister(vdpasim_net_mgmtdev); | |
| 568 | 559 | return ret; |
| 569 | 560 | } |
| 570 | 561 | |
| 571 | 562 | static void __exit vdpasim_net_exit(void) |
| 572 | 563 | { |
| 573 | 564 | vdpa_mgmtdev_unregister(&mgmt_dev); |
| 574 | − device_unregister(&vdpasim_net_mgmtdev); | |
| 565 | + root_device_unregister(vdpasim_net_mgmtdev); | |
| 575 | 566 | } |
| 576 | 567 | |
| 577 | 568 | module_init(vdpasim_net_init); |
| @@ -124,7 +124,7 @@ static int vduse_domain_map_bounce_page(struct vduse_iova_domain *domain, · 123 unmodified lines | ||
| 124 | 124 | if (!map->bounce_page) { |
| 125 | 125 | head_map = &domain->bounce_maps[(iova & PAGE_MASK) >> BOUNCE_MAP_SHIFT]; |
| 126 | 126 | if (!head_map->bounce_page) { |
| 127 | − tmp_page = alloc_page(GFP_ATOMIC); | |
| 127 | + tmp_page = alloc_page(GFP_ATOMIC | __GFP_ZERO); | |
| 128 | 128 | if (!tmp_page) |
| 129 | 129 | return -ENOMEM; |
| 130 | 130 | if (cmpxchg(&head_map->bounce_page, NULL, tmp_page)) |
| @@ -221,6 +221,12 @@ static void vduse_enqueue_msg(struct list_head *head, · 220 unmodified lines | ||
| 221 | 221 | list_add_tail(&msg->list, head); |
| 222 | 222 | } |
| 223 | 223 | |
| 224 | +static void vduse_enqueue_msg_head(struct list_head *head, | |
| 225 | + struct vduse_dev_msg *msg) | |
| 226 | +{ | |
| 227 | + list_add(&msg->list, head); | |
| 228 | +} | |
| 229 | + | |
| 224 | 230 | static void vduse_dev_broken(struct vduse_dev *dev) |
| 225 | 231 | { |
| 226 | 232 | struct vduse_dev_msg *msg, *tmp; |
| @@ -358,6 +364,7 @@ static ssize_t vduse_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) · 131 unmodified lines | ||
| 358 | 364 | struct file *file = iocb->ki_filp; |
| 359 | 365 | struct vduse_dev *dev = file->private_data; |
| 360 | 366 | struct vduse_dev_msg *msg; |
| 367 | + struct vduse_dev_request req; | |
| 361 | 368 | int size = sizeof(struct vduse_dev_request); |
| 362 | 369 | ssize_t ret; |
| 363 | 370 | |
| @@ -369,12 +376,11 @@ static ssize_t vduse_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) · 5 unmodified lines | ||
| 369 | 376 | msg = vduse_dequeue_msg(&dev->send_list); |
| 370 | 377 | if (msg) |
| 371 | 378 | break; |
| 379 | + spin_unlock(&dev->msg_lock); | |
| 372 | 380 | |
| 373 | − ret = -EAGAIN; | |
| 374 | 381 | if (file->f_flags & O_NONBLOCK) |
| 375 | − goto unlock; | |
| 382 | + return -EAGAIN; | |
| 376 | 383 | |
| 377 | − spin_unlock(&dev->msg_lock); | |
| 378 | 384 | ret = wait_event_interruptible_exclusive(dev->waitq, |
| 379 | 385 | !list_empty(&dev->send_list)); |
| 380 | 386 | if (ret) |
| @@ -382,17 +388,34 @@ static ssize_t vduse_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) · 1 unmodified line | ||
| 382 | 388 | |
| 383 | 389 | spin_lock(&dev->msg_lock); |
| 384 | 390 | } |
| 391 | + | |
| 392 | + memcpy(&req, &msg->req, sizeof(req)); | |
| 393 | + /* | |
| 394 | + * We must ensure vduse_msg is on send_list or recv_list before unlock | |
| 395 | + * dev->msg_lock. Because vduse_dev_msg_sync() may be timeout when we | |
| 396 | + * copy data to userspace, and will call list_del() for this msg. | |
| 397 | + */ | |
| 398 | + vduse_enqueue_msg(&dev->recv_list, msg); | |
| 385 | 399 | spin_unlock(&dev->msg_lock); |
| 386 | − ret = copy_to_iter(&msg->req, size, to); | |
| 387 | − spin_lock(&dev->msg_lock); | |
| 400 | + | |
| 401 | + ret = copy_to_iter(&req, size, to); | |
| 388 | 402 | if (ret != size) { |
| 403 | + /* | |
| 404 | + * Roll back: move msg back to send_list if still pending. | |
| 405 | + * | |
| 406 | + * NOTE: | |
| 407 | + * vduse_find_msg() must use req.request_id instead of `msg`. | |
| 408 | + * A malicious userspace may reply to this request, and wake up | |
| 409 | + * the caller, after which `msg` will have already been freed. | |
| 410 | + * And here vduse_find_msg() will return NULL then do nothing. | |
| 411 | + */ | |
| 412 | + spin_lock(&dev->msg_lock); | |
| 413 | + msg = vduse_find_msg(&dev->recv_list, req.request_id); | |
| 414 | + if (msg) | |
| 415 | + vduse_enqueue_msg_head(&dev->send_list, msg); | |
| 416 | + spin_unlock(&dev->msg_lock); | |
| 389 | 417 | ret = -EFAULT; |
| 390 | − vduse_enqueue_msg(&dev->send_list, msg); | |
| 391 | − goto unlock; | |
| 392 | 418 | } |
| 393 | − vduse_enqueue_msg(&dev->recv_list, msg); | |
| 394 | −unlock: | |
| 395 | − spin_unlock(&dev->msg_lock); | |
| 396 | 419 | |
| 397 | 420 | return ret; |
| 398 | 421 | } |
| @@ -976,7 +999,7 @@ static void *vduse_dev_alloc_coherent(union virtio_map token, size_t size, · 577 unmodified lines | ||
| 976 | 999 | if (!token.group) |
| 977 | 1000 | return NULL; |
| 978 | 1001 | |
| 979 | − addr = alloc_pages_exact(size, flag); | |
| 1002 | + addr = alloc_pages_exact(size, flag | __GFP_ZERO); | |
| 980 | 1003 | if (!addr) |
| 981 | 1004 | return NULL; |
| 982 | 1005 | |
| @@ -1618,6 +1641,127 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, · 635 unmodified lines | ||
| 1618 | 1641 | return ret; |
| 1619 | 1642 | } |
| 1620 | 1643 | |
| 1644 | +#ifdef CONFIG_COMPAT_FOR_U64_ALIGNMENT | |
| 1645 | +/* | |
| 1646 | + * i386 has different alignment constraints than x86_64, | |
| 1647 | + * so there are only 3 bytes of padding instead of 7. | |
| 1648 | + */ | |
| 1649 | +struct compat_vduse_iotlb_entry { | |
| 1650 | + compat_u64 offset; | |
| 1651 | + compat_u64 start; | |
| 1652 | + compat_u64 last; | |
| 1653 | + __u8 perm; | |
| 1654 | + __u8 padding[3]; | |
| 1655 | +}; | |
| 1656 | +#define COMPAT_VDUSE_IOTLB_GET_FD _IOWR(VDUSE_BASE, 0x10, struct compat_vduse_iotlb_entry) | |
| 1657 | + | |
| 1658 | +struct compat_vduse_vq_info { | |
| 1659 | + __u32 index; | |
| 1660 | + __u32 num; | |
| 1661 | + compat_u64 desc_addr; | |
| 1662 | + compat_u64 driver_addr; | |
| 1663 | + compat_u64 device_addr; | |
| 1664 | + union { | |
| 1665 | + struct vduse_vq_state_split split; | |
| 1666 | + struct vduse_vq_state_packed packed; | |
| 1667 | + }; | |
| 1668 | + __u8 ready; | |
| 1669 | + __u8 padding[3]; | |
| 1670 | +}; | |
| 1671 | +#define COMPAT_VDUSE_VQ_GET_INFO _IOWR(VDUSE_BASE, 0x15, struct compat_vduse_vq_info) | |
| 1672 | + | |
| 1673 | +static long vduse_dev_compat_ioctl(struct file *file, unsigned int cmd, | |
| 1674 | + unsigned long arg) | |
| 1675 | +{ | |
| 1676 | + struct vduse_dev *dev = file->private_data; | |
| 1677 | + void __user *argp = (void __user *)arg; | |
| 1678 | + int ret; | |
| 1679 | + | |
| 1680 | + if (unlikely(dev->broken)) | |
| 1681 | + return -EPERM; | |
| 1682 | + | |
| 1683 | + switch (cmd) { | |
| 1684 | + case COMPAT_VDUSE_IOTLB_GET_FD: { | |
| 1685 | + struct vduse_iotlb_entry_v2 entry = {0}; | |
| 1686 | + struct file *f = NULL; | |
| 1687 | + | |
| 1688 | + ret = -EFAULT; | |
| 1689 | + if (copy_from_user(&entry, argp, _IOC_SIZE(cmd))) | |
| 1690 | + break; | |
| 1691 | + | |
| 1692 | + ret = vduse_dev_iotlb_entry(dev, &entry, &f, NULL); | |
| 1693 | + if (ret) | |
| 1694 | + break; | |
| 1695 | + | |
| 1696 | + ret = -EINVAL; | |
| 1697 | + if (!f) | |
| 1698 | + break; | |
| 1699 | + | |
| 1700 | + ret = copy_to_user(argp, &entry, _IOC_SIZE(cmd)); | |
| 1701 | + if (ret) { | |
| 1702 | + ret = -EFAULT; | |
| 1703 | + fput(f); | |
| 1704 | + break; | |
| 1705 | + } | |
| 1706 | + ret = receive_fd(f, NULL, perm_to_file_flags(entry.perm)); | |
| 1707 | + fput(f); | |
| 1708 | + break; | |
| 1709 | + } | |
| 1710 | + case COMPAT_VDUSE_VQ_GET_INFO: { | |
| 1711 | + struct vduse_vq_info vq_info = {}; | |
| 1712 | + struct vduse_virtqueue *vq; | |
| 1713 | + u32 index; | |
| 1714 | + | |
| 1715 | + ret = -EFAULT; | |
| 1716 | + if (copy_from_user(&vq_info, argp, | |
| 1717 | + sizeof(struct compat_vduse_vq_info))) | |
| 1718 | + break; | |
| 1719 | + | |
| 1720 | + ret = -EINVAL; | |
| 1721 | + if (vq_info.index >= dev->vq_num) | |
| 1722 | + break; | |
| 1723 | + | |
| 1724 | + index = array_index_nospec(vq_info.index, dev->vq_num); | |
| 1725 | + vq = dev->vqs[index]; | |
| 1726 | + vq_info.desc_addr = vq->desc_addr; | |
| 1727 | + vq_info.driver_addr = vq->driver_addr; | |
| 1728 | + vq_info.device_addr = vq->device_addr; | |
| 1729 | + vq_info.num = vq->num; | |
| 1730 | + | |
| 1731 | + if (dev->driver_features & BIT_ULL(VIRTIO_F_RING_PACKED)) { | |
| 1732 | + vq_info.packed.last_avail_counter = | |
| 1733 | + vq->state.packed.last_avail_counter; | |
| 1734 | + vq_info.packed.last_avail_idx = | |
| 1735 | + vq->state.packed.last_avail_idx; | |
| 1736 | + vq_info.packed.last_used_counter = | |
| 1737 | + vq->state.packed.last_used_counter; | |
| 1738 | + vq_info.packed.last_used_idx = | |
| 1739 | + vq->state.packed.last_used_idx; | |
| 1740 | + } else | |
| 1741 | + vq_info.split.avail_index = | |
| 1742 | + vq->state.split.avail_index; | |
| 1743 | + | |
| 1744 | + vq_info.ready = vq->ready; | |
| 1745 | + | |
| 1746 | + ret = -EFAULT; | |
| 1747 | + if (copy_to_user(argp, &vq_info, | |
| 1748 | + sizeof(struct compat_vduse_vq_info))) | |
| 1749 | + break; | |
| 1750 | + | |
| 1751 | + ret = 0; | |
| 1752 | + break; | |
| 1753 | + } | |
| 1754 | + default: | |
| 1755 | + ret = -ENOIOCTLCMD; | |
| 1756 | + break; | |
| 1757 | + } | |
| 1758 | + | |
| 1759 | + return vduse_dev_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); | |
| 1760 | +} | |
| 1761 | +#else | |
| 1762 | +#define vduse_dev_compat_ioctl compat_ptr_ioctl | |
| 1763 | +#endif | |
| 1764 | + | |
| 1621 | 1765 | static int vduse_dev_release(struct inode *inode, struct file *file) |
| 1622 | 1766 | { |
| 1623 | 1767 | struct vduse_dev *dev = file->private_data; |
| @@ -1637,26 +1781,18 @@ static int vduse_dev_release(struct inode *inode, struct file *file) · 13 unmodified lines | ||
| 1637 | 1781 | return 0; |
| 1638 | 1782 | } |
| 1639 | 1783 | |
| 1640 | −static struct vduse_dev *vduse_dev_get_from_minor(int minor) | |
| 1784 | +static int vduse_dev_open(struct inode *inode, struct file *file) | |
| 1641 | 1785 | { |
| 1786 | + int ret = -EBUSY; | |
| 1642 | 1787 | struct vduse_dev *dev; |
| 1643 | 1788 | |
| 1644 | 1789 | mutex_lock(&vduse_lock); |
| 1645 | − dev = idr_find(&vduse_idr, minor); | |
| 1646 | − mutex_unlock(&vduse_lock); | |
| 1647 | − | |
| 1648 | − return dev; | |
| 1649 | −} | |
| 1650 | − | |
| 1651 | −static int vduse_dev_open(struct inode *inode, struct file *file) | |
| 1652 | −{ | |
| 1653 | − int ret; | |
| 1654 | − struct vduse_dev *dev = vduse_dev_get_from_minor(iminor(inode)); | |
| 1655 | − | |
| 1656 | − if (!dev) | |
| 1790 | + dev = idr_find(&vduse_idr, iminor(inode)); | |
| 1791 | + if (!dev) { | |
| 1792 | + mutex_unlock(&vduse_lock); | |
| 1657 | 1793 | return -ENODEV; |
| 1794 | + } | |
| 1658 | 1795 | |
| 1659 | − ret = -EBUSY; | |
| 1660 | 1796 | mutex_lock(&dev->lock); |
| 1661 | 1797 | if (dev->connected) |
| 1662 | 1798 | goto unlock; |
| @@ -1666,6 +1802,7 @@ static int vduse_dev_open(struct inode *inode, struct file *file) · 3 unmodified lines | ||
| 1666 | 1802 | file->private_data = dev; |
| 1667 | 1803 | unlock: |
| 1668 | 1804 | mutex_unlock(&dev->lock); |
| 1805 | + mutex_unlock(&vduse_lock); | |
| 1669 | 1806 | |
| 1670 | 1807 | return ret; |
| 1671 | 1808 | } |
| @@ -1678,7 +1815,7 @@ static const struct file_operations vduse_dev_fops = { · 6 unmodified lines | ||
| 1678 | 1815 | .write_iter = vduse_dev_write_iter, |
| 1679 | 1816 | .poll = vduse_dev_poll, |
| 1680 | 1817 | .unlocked_ioctl = vduse_dev_ioctl, |
| 1681 | − .compat_ioctl = compat_ptr_ioctl, | |
| 1818 | + .compat_ioctl = vduse_dev_compat_ioctl, | |
| 1682 | 1819 | .llseek = noop_llseek, |
| 1683 | 1820 | }; |
| 1684 | 1821 | |
| @@ -399,13 +399,20 @@ static void vhost_zerocopy_signal_used(struct vhost_net *net, · 398 unmodified lines | ||
| 399 | 399 | static void vhost_zerocopy_complete(struct sk_buff *skb, |
| 400 | 400 | struct ubuf_info *ubuf_base, bool success) |
| 401 | 401 | { |
| 402 | − struct ubuf_info_msgzc *ubuf = uarg_to_msgzc(ubuf_base); | |
| 403 | − struct vhost_net_ubuf_ref *ubufs = ubuf->ctx; | |
| 404 | − struct vhost_virtqueue *vq = ubufs->vq; | |
| 402 | + struct ubuf_info_msgzc *ubuf; | |
| 403 | + struct vhost_net_ubuf_ref *ubufs; | |
| 404 | + struct vhost_virtqueue *vq; | |
| 405 | 405 | int cnt; |
| 406 | 406 | |
| 407 | − rcu_read_lock_bh(); | |
| 407 | + /* Only the final cloned skb reference completes the vhost descriptor. */ | |
| 408 | + if (!refcount_dec_and_test(&ubuf_base->refcnt)) | |
| 409 | + return; | |
| 410 | + | |
| 411 | + ubuf = uarg_to_msgzc(ubuf_base); | |
| 412 | + ubufs = ubuf->ctx; | |
| 413 | + vq = ubufs->vq; | |
| 408 | 414 | |
| 415 | + rcu_read_lock_bh(); | |
| 409 | 416 | /* set len to mark this desc buffers done DMA */ |
| 410 | 417 | vq->heads[ubuf->desc].len = success ? |
| 411 | 418 | VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN; |
| @@ -1482,16 +1482,32 @@ static int vhost_vdpa_release(struct inode *inode, struct file *filep) · 1481 unmodified lines | ||
| 1482 | 1482 | } |
| 1483 | 1483 | |
| 1484 | 1484 | #ifdef CONFIG_MMU |
| 1485 | −static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf) | |
| 1485 | +static int | |
| 1486 | +vhost_vdpa_get_vq_notification(struct vhost_vdpa *v, unsigned long index, | |
| 1487 | + struct vdpa_notification_area *notify) | |
| 1486 | 1488 | { |
| 1487 | − struct vhost_vdpa *v = vmf->vma->vm_file->private_data; | |
| 1488 | 1489 | struct vdpa_device *vdpa = v->vdpa; |
| 1489 | 1490 | const struct vdpa_config_ops *ops = vdpa->config; |
| 1491 | + | |
| 1492 | + if (index > 65535 || index >= v->nvqs) | |
| 1493 | + return -EINVAL; | |
| 1494 | + | |
| 1495 | + index = array_index_nospec(index, v->nvqs); | |
| 1496 | + | |
| 1497 | + *notify = ops->get_vq_notification(vdpa, index); | |
| 1498 | + | |
| 1499 | + return 0; | |
| 1500 | +} | |
| 1501 | + | |
| 1502 | +static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf) | |
| 1503 | +{ | |
| 1504 | + struct vhost_vdpa *v = vmf->vma->vm_file->private_data; | |
| 1490 | 1505 | struct vdpa_notification_area notify; |
| 1491 | 1506 | struct vm_area_struct *vma = vmf->vma; |
| 1492 | − u16 index = vma->vm_pgoff; | |
| 1507 | + unsigned long index = vma->vm_pgoff; | |
| 1493 | 1508 | |
| 1494 | − notify = ops->get_vq_notification(vdpa, index); | |
| 1509 | + if (vhost_vdpa_get_vq_notification(v, index, ¬ify)) | |
| 1510 | + return VM_FAULT_SIGBUS; | |
| 1495 | 1511 | |
| 1496 | 1512 | return vmf_insert_pfn(vma, vmf->address & PAGE_MASK, PFN_DOWN(notify.addr)); |
| 1497 | 1513 | } |
| @@ -1514,8 +1530,6 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma) · 16 unmodified lines | ||
| 1514 | 1530 | return -EINVAL; |
| 1515 | 1531 | if (vma->vm_flags & VM_READ) |
| 1516 | 1532 | return -EINVAL; |
| 1517 | − if (index > 65535) | |
| 1518 | − return -EINVAL; | |
| 1519 | 1533 | if (!ops->get_vq_notification) |
| 1520 | 1534 | return -ENOTSUPP; |
| 1521 | 1535 | |
| @@ -1523,7 +1537,8 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma) · 1 unmodified line | ||
| 1523 | 1537 | * support the doorbell which sits on the page boundary and |
| 1524 | 1538 | * does not share the page with other registers. |
| 1525 | 1539 | */ |
| 1526 | − notify = ops->get_vq_notification(vdpa, index); | |
| 1540 | + if (vhost_vdpa_get_vq_notification(v, index, ¬ify)) | |
| 1541 | + return -EINVAL; | |
| 1527 | 1542 | if (notify.addr & (PAGE_SIZE - 1)) |
| 1528 | 1543 | return -EINVAL; |
| 1529 | 1544 | if (vma->vm_end - vma->vm_start != notify.size) |
| @@ -1522,6 +1522,7 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d) · 1521 unmodified lines | ||
| 1522 | 1522 | static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq) |
| 1523 | 1523 | { |
| 1524 | 1524 | __virtio16 idx; |
| 1525 | + u16 avail_idx; | |
| 1525 | 1526 | int r; |
| 1526 | 1527 | |
| 1527 | 1528 | r = vhost_get_avail(vq, idx, &vq->avail->idx); |
| @@ -1532,17 +1533,19 @@ static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq) · 4 unmodified lines | ||
| 1532 | 1533 | } |
| 1533 | 1534 | |
| 1534 | 1535 | /* Check it isn't doing very strange thing with available indexes */ |
| 1535 | − vq->avail_idx = vhost16_to_cpu(vq, idx); | |
| 1536 | − if (unlikely((u16)(vq->avail_idx - vq->last_avail_idx) > vq->num)) { | |
| 1536 | + avail_idx = vhost16_to_cpu(vq, idx); | |
| 1537 | + if (unlikely((u16)(avail_idx - vq->last_avail_idx) > vq->num)) { | |
| 1537 | 1538 | vq_err(vq, "Invalid available index change from %u to %u", |
| 1538 | − vq->last_avail_idx, vq->avail_idx); | |
| 1539 | + vq->last_avail_idx, avail_idx); | |
| 1539 | 1540 | return -EINVAL; |
| 1540 | 1541 | } |
| 1541 | 1542 | |
| 1542 | 1543 | /* We're done if there is nothing new */ |
| 1543 | − if (vq->avail_idx == vq->last_avail_idx) | |
| 1544 | + if (avail_idx == vq->avail_idx) | |
| 1544 | 1545 | return 0; |
| 1545 | 1546 | |
| 1547 | + vq->avail_idx = avail_idx; | |
| 1548 | + | |
| 1546 | 1549 | /* |
| 1547 | 1550 | * We updated vq->avail_idx so we need a memory barrier between |
| 1548 | 1551 | * the index read above and the caller reading avail ring entries. |
| @@ -3321,18 +3324,6 @@ void vhost_set_backend_features(struct vhost_dev *dev, u64 features) · 1772 unmodified lines | ||
| 3321 | 3324 | } |
| 3322 | 3325 | EXPORT_SYMBOL_GPL(vhost_set_backend_features); |
| 3323 | 3326 | |
| 3324 | −static int __init vhost_init(void) | |
| 3325 | −{ | |
| 3326 | − return 0; | |
| 3327 | −} | |
| 3328 | − | |
| 3329 | −static void __exit vhost_exit(void) | |
| 3330 | −{ | |
| 3331 | −} | |
| 3332 | − | |
| 3333 | −module_init(vhost_init); | |
| 3334 | −module_exit(vhost_exit); | |
| 3335 | − | |
| 3336 | 3327 | MODULE_VERSION("0.0.1"); |
| 3337 | 3328 | MODULE_LICENSE("GPL v2"); |
| 3338 | 3329 | MODULE_AUTHOR("Michael S. Tsirkin"); |
| @@ -302,6 +302,22 @@ vhost_transport_send_pkt(struct sk_buff *skb, struct net *net) · 301 unmodified lines | ||
| 302 | 302 | return -ENODEV; |
| 303 | 303 | } |
| 304 | 304 | |
| 305 | + /* Fast-fail if the guest hasn't enabled the RX vq yet. Queuing the packet | |
| 306 | + * and making the caller wait is pointless: even if the guest manages to init | |
| 307 | + * within the timeout, it'll immediately reply with RST, because there's no | |
| 308 | + * listener on the port yet. | |
| 309 | + * | |
| 310 | + * vhost_vq_get_backend() without vq->mutex is acceptable here: locking | |
| 311 | + * the mutex would be too expensive in this hot path, and we already have | |
| 312 | + * all the outcomes covered: if the backend becomes NULL right after the check, | |
| 313 | + * vhost_transport_do_send_pkt() will check it under the mutex anyway. | |
| 314 | + */ | |
| 315 | + if (unlikely(!data_race(vhost_vq_get_backend(&vsock->vqs[VSOCK_VQ_RX])))) { | |
| 316 | + rcu_read_unlock(); | |
| 317 | + kfree_skb(skb); | |
| 318 | + return -EHOSTUNREACH; | |
| 319 | + } | |
| 320 | + | |
| 305 | 321 | if (virtio_vsock_skb_reply(skb)) |
| 306 | 322 | atomic_inc(&vsock->queued_replies); |
| 307 | 323 | |
| @@ -435,6 +435,14 @@ static void virtio_dev_shutdown(struct device *_d) · 434 unmodified lines | ||
| 435 | 435 | dev->config->reset(dev); |
| 436 | 436 | } |
| 437 | 437 | |
| 438 | +static int virtio_dev_num_vf(struct device *dev) | |
| 439 | +{ | |
| 440 | + struct virtio_device *vdev = dev_to_virtio(dev); | |
| 441 | + | |
| 442 | + return dev_num_vf(vdev->dev.parent); | |
| 443 | +} | |
| 444 | + | |
| 445 | + | |
| 438 | 446 | static const struct bus_type virtio_bus = { |
| 439 | 447 | .name = "virtio", |
| 440 | 448 | .match = virtio_dev_match, |
| @@ -444,6 +452,7 @@ static const struct bus_type virtio_bus = { · 3 unmodified lines | ||
| 444 | 452 | .remove = virtio_dev_remove, |
| 445 | 453 | .irq_get_affinity = virtio_irq_get_affinity, |
| 446 | 454 | .shutdown = virtio_dev_shutdown, |
| 455 | + .num_vf = virtio_dev_num_vf, | |
| 447 | 456 | }; |
| 448 | 457 | |
| 449 | 458 | int __register_virtio_driver(struct virtio_driver *driver, struct module *owner) |
| @@ -1075,6 +1075,7 @@ out_del_balloon_wq: · 1074 unmodified lines | ||
| 1075 | 1075 | out_del_vqs: |
| 1076 | 1076 | vdev->config->del_vqs(vdev); |
| 1077 | 1077 | out_free_vb: |
| 1078 | + mutex_destroy(&vb->balloon_lock); | |
| 1078 | 1079 | kfree(vb); |
| 1079 | 1080 | out: |
| 1080 | 1081 | return err; |
| @@ -1119,6 +1120,7 @@ static void virtballoon_remove(struct virtio_device *vdev) · 38 unmodified lines | ||
| 1119 | 1120 | } |
| 1120 | 1121 | |
| 1121 | 1122 | remove_common(vb); |
| 1123 | + mutex_destroy(&vb->balloon_lock); | |
| 1122 | 1124 | kfree(vb); |
| 1123 | 1125 | } |
| 1124 | 1126 | |
| @@ -2975,6 +2975,7 @@ static int virtio_mem_probe(struct virtio_device *vdev) · 2974 unmodified lines | ||
| 2975 | 2975 | out_del_vq: |
| 2976 | 2976 | vdev->config->del_vqs(vdev); |
| 2977 | 2977 | out_free_vm: |
| 2978 | + mutex_destroy(&vm->hotplug_mutex); | |
| 2978 | 2979 | kfree(vm); |
| 2979 | 2980 | vdev->priv = NULL; |
| 2980 | 2981 | |
| @@ -3067,6 +3068,7 @@ static void virtio_mem_remove(struct virtio_device *vdev) · 86 unmodified lines | ||
| 3067 | 3068 | virtio_reset_device(vdev); |
| 3068 | 3069 | vdev->config->del_vqs(vdev); |
| 3069 | 3070 | |
| 3071 | + mutex_destroy(&vm->hotplug_mutex); | |
| 3070 | 3072 | kfree(vm); |
| 3071 | 3073 | vdev->priv = NULL; |
| 3072 | 3074 | } |
| @@ -662,9 +662,7 @@ static void virtio_mmio_remove(struct platform_device *pdev) · 661 unmodified lines | ||
| 662 | 662 | |
| 663 | 663 | #if defined(CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES) |
| 664 | 664 | |
| 665 | −static struct device vm_cmdline_parent = { | |
| 666 | − .init_name = "virtio-mmio-cmdline", | |
| 667 | −}; | |
| 665 | +static struct device *vm_cmdline_parent; | |
| 668 | 666 | |
| 669 | 667 | static int vm_cmdline_parent_registered; |
| 670 | 668 | static int vm_cmdline_id; |
| @@ -672,7 +670,6 @@ static int vm_cmdline_id; · 1 unmodified line | ||
| 672 | 670 | static int vm_cmdline_set(const char *device, |
| 673 | 671 | const struct kernel_param *kp) |
| 674 | 672 | { |
| 675 | − int err; | |
| 676 | 673 | struct resource resources[2] = {}; |
| 677 | 674 | char *str; |
| 678 | 675 | long long base, size; |
| @@ -704,11 +701,10 @@ static int vm_cmdline_set(const char *device, · 25 unmodified lines | ||
| 704 | 701 | resources[1].start = resources[1].end = irq; |
| 705 | 702 | |
| 706 | 703 | if (!vm_cmdline_parent_registered) { |
| 707 | − err = device_register(&vm_cmdline_parent); | |
| 708 | − if (err) { | |
| 709 | − put_device(&vm_cmdline_parent); | |
| 704 | + vm_cmdline_parent = __root_device_register("virtio-mmio-cmdline", NULL); | |
| 705 | + if (IS_ERR(vm_cmdline_parent)) { | |
| 710 | 706 | pr_err("Failed to register parent device!\n"); |
| 711 | − return err; | |
| 707 | + return PTR_ERR(vm_cmdline_parent); | |
| 712 | 708 | } |
| 713 | 709 | vm_cmdline_parent_registered = 1; |
| 714 | 710 | } |
| @@ -719,7 +715,7 @@ static int vm_cmdline_set(const char *device, · 4 unmodified lines | ||
| 719 | 715 | (unsigned long long)resources[0].end, |
| 720 | 716 | (int)resources[1].start); |
| 721 | 717 | |
| 722 | − pdev = platform_device_register_resndata(&vm_cmdline_parent, | |
| 718 | + pdev = platform_device_register_resndata(vm_cmdline_parent, | |
| 723 | 719 | "virtio-mmio", vm_cmdline_id++, |
| 724 | 720 | resources, ARRAY_SIZE(resources), NULL, 0); |
| 725 | 721 | |
| @@ -743,8 +739,12 @@ static int vm_cmdline_get_device(struct device *dev, void *data) · 17 unmodified lines | ||
| 743 | 739 | static int vm_cmdline_get(char *buffer, const struct kernel_param *kp) |
| 744 | 740 | { |
| 745 | 741 | buffer[0] = '\0'; |
| 746 | − device_for_each_child(&vm_cmdline_parent, buffer, | |
| 747 | − vm_cmdline_get_device); | |
| 742 | + | |
| 743 | + if (vm_cmdline_parent_registered) { | |
| 744 | + device_for_each_child(vm_cmdline_parent, buffer, | |
| 745 | + vm_cmdline_get_device); | |
| 746 | + } | |
| 747 | + | |
| 748 | 748 | return strlen(buffer) + 1; |
| 749 | 749 | } |
| 750 | 750 | |
| @@ -766,9 +766,9 @@ static int vm_unregister_cmdline_device(struct device *dev, · 15 unmodified lines | ||
| 766 | 766 | static void vm_unregister_cmdline_devices(void) |
| 767 | 767 | { |
| 768 | 768 | if (vm_cmdline_parent_registered) { |
| 769 | − device_for_each_child(&vm_cmdline_parent, NULL, | |
| 769 | + device_for_each_child(vm_cmdline_parent, NULL, | |
| 770 | 770 | vm_unregister_cmdline_device); |
| 771 | − device_unregister(&vm_cmdline_parent); | |
| 771 | + root_device_unregister(vm_cmdline_parent); | |
| 772 | 772 | vm_cmdline_parent_registered = 0; |
| 773 | 773 | } |
| 774 | 774 | } |
| @@ -423,10 +423,11 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs, · 422 unmodified lines | ||
| 423 | 423 | vqs[i] = NULL; |
| 424 | 424 | continue; |
| 425 | 425 | } |
| 426 | − vqs[i] = vp_find_one_vq_msix(vdev, queue_idx++, vqi->callback, | |
| 426 | + vqs[i] = vp_find_one_vq_msix(vdev, queue_idx, vqi->callback, | |
| 427 | 427 | vqi->name, vqi->ctx, false, |
| 428 | 428 | &allocated_vectors, vector_policy, |
| 429 | − &vp_dev->vqs[i]); | |
| 429 | + &vp_dev->vqs[queue_idx]); | |
| 430 | + queue_idx++; | |
| 430 | 431 | if (IS_ERR(vqs[i])) { |
| 431 | 432 | err = PTR_ERR(vqs[i]); |
| 432 | 433 | goto error_find; |
| @@ -485,9 +486,10 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs, · 52 unmodified lines | ||
| 485 | 486 | vqs[i] = NULL; |
| 486 | 487 | continue; |
| 487 | 488 | } |
| 488 | − vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback, | |
| 489 | + vqs[i] = vp_setup_vq(vdev, queue_idx, vqi->callback, | |
| 489 | 490 | vqi->name, vqi->ctx, |
| 490 | − VIRTIO_MSI_NO_VECTOR, &vp_dev->vqs[i]); | |
| 491 | + VIRTIO_MSI_NO_VECTOR, &vp_dev->vqs[queue_idx]); | |
| 492 | + queue_idx++; | |
| 491 | 493 | if (IS_ERR(vqs[i])) { |
| 492 | 494 | err = PTR_ERR(vqs[i]); |
| 493 | 495 | goto out_del_vqs; |
| @@ -272,6 +272,55 @@ struct vring_virtqueue { · 271 unmodified lines | ||
| 272 | 272 | #endif |
| 273 | 273 | }; |
| 274 | 274 | |
| 275 | +/* | |
| 276 | + * Accessors for device-writable fields in virtio rings. | |
| 277 | + * These fields are concurrently written by the device and read by the driver. | |
| 278 | + * Use READ_ONCE() to prevent compiler optimizations, document the | |
| 279 | + * intentional data race and prevent KCSAN warnings. | |
| 280 | + */ | |
| 281 | +static inline u16 vring_read_split_used_idx(const struct vring_virtqueue *vq) | |
| 282 | +{ | |
| 283 | + return virtio16_to_cpu(vq->vq.vdev, | |
| 284 | + READ_ONCE(vq->split.vring.used->idx)); | |
| 285 | +} | |
| 286 | + | |
| 287 | +static inline u32 vring_read_split_used_id(const struct vring_virtqueue *vq, | |
| 288 | + u16 idx) | |
| 289 | +{ | |
| 290 | + return virtio32_to_cpu(vq->vq.vdev, | |
| 291 | + READ_ONCE(vq->split.vring.used->ring[idx].id)); | |
| 292 | +} | |
| 293 | + | |
| 294 | +static inline u32 vring_read_split_used_len(const struct vring_virtqueue *vq, u16 idx) | |
| 295 | +{ | |
| 296 | + return virtio32_to_cpu(vq->vq.vdev, | |
| 297 | + READ_ONCE(vq->split.vring.used->ring[idx].len)); | |
| 298 | +} | |
| 299 | + | |
| 300 | +static inline u16 vring_read_split_avail_event(const struct vring_virtqueue *vq) | |
| 301 | +{ | |
| 302 | + return virtio16_to_cpu(vq->vq.vdev, | |
| 303 | + READ_ONCE(vring_avail_event(&vq->split.vring))); | |
| 304 | +} | |
| 305 | + | |
| 306 | +static inline u16 vring_read_packed_desc_flags(const struct vring_virtqueue *vq, | |
| 307 | + u16 idx) | |
| 308 | +{ | |
| 309 | + return le16_to_cpu(READ_ONCE(vq->packed.vring.desc[idx].flags)); | |
| 310 | +} | |
| 311 | + | |
| 312 | +static inline u16 vring_read_packed_desc_id(const struct vring_virtqueue *vq, | |
| 313 | + u16 idx) | |
| 314 | +{ | |
| 315 | + return le16_to_cpu(READ_ONCE(vq->packed.vring.desc[idx].id)); | |
| 316 | +} | |
| 317 | + | |
| 318 | +static inline u32 vring_read_packed_desc_len(const struct vring_virtqueue *vq, | |
| 319 | + u16 idx) | |
| 320 | +{ | |
| 321 | + return le32_to_cpu(READ_ONCE(vq->packed.vring.desc[idx].len)); | |
| 322 | +} | |
| 323 | + | |
| 275 | 324 | static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num); |
| 276 | 325 | static void vring_free(struct virtqueue *_vq); |
| 277 | 326 | |
| @@ -809,8 +858,7 @@ static bool virtqueue_kick_prepare_split(struct vring_virtqueue *vq) · 531 unmodified lines | ||
| 809 | 858 | LAST_ADD_TIME_INVALID(vq); |
| 810 | 859 | |
| 811 | 860 | if (vq->event) { |
| 812 | − needs_kick = vring_need_event(virtio16_to_cpu(vq->vq.vdev, | |
| 813 | − vring_avail_event(&vq->split.vring)), | |
| 861 | + needs_kick = vring_need_event(vring_read_split_avail_event(vq), | |
| 814 | 862 | new, old); |
| 815 | 863 | } else { |
| 816 | 864 | needs_kick = !(vq->split.vring.used->flags & |
| @@ -897,8 +945,7 @@ static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head, · 80 unmodified lines | ||
| 897 | 945 | static bool virtqueue_poll_split(const struct vring_virtqueue *vq, |
| 898 | 946 | unsigned int last_used_idx) |
| 899 | 947 | { |
| 900 | − return (u16)last_used_idx != virtio16_to_cpu(vq->vq.vdev, | |
| 901 | − vq->split.vring.used->idx); | |
| 948 | + return (u16)last_used_idx != vring_read_split_used_idx(vq); | |
| 902 | 949 | } |
| 903 | 950 | |
| 904 | 951 | static bool more_used_split(const struct vring_virtqueue *vq) |
| @@ -939,10 +986,8 @@ static void *virtqueue_get_buf_ctx_split(struct vring_virtqueue *vq, · 34 unmodified lines | ||
| 939 | 986 | virtio_rmb(vq->weak_barriers); |
| 940 | 987 | |
| 941 | 988 | last_used = (vq->last_used_idx & (vq->split.vring.num - 1)); |
| 942 | − i = virtio32_to_cpu(vq->vq.vdev, | |
| 943 | − vq->split.vring.used->ring[last_used].id); | |
| 944 | − *len = virtio32_to_cpu(vq->vq.vdev, | |
| 945 | − vq->split.vring.used->ring[last_used].len); | |
| 989 | + i = vring_read_split_used_id(vq, last_used); | |
| 990 | + *len = vring_read_split_used_len(vq, last_used); | |
| 946 | 991 | |
| 947 | 992 | if (unlikely(i >= vq->split.vring.num)) { |
| 948 | 993 | BAD_RING(vq, "id %u out of range\n", i); |
| @@ -1003,10 +1048,8 @@ static void *virtqueue_get_buf_ctx_split_in_order(struct vring_virtqueue *vq, · 54 unmodified lines | ||
| 1003 | 1048 | */ |
| 1004 | 1049 | virtio_rmb(vq->weak_barriers); |
| 1005 | 1050 | |
| 1006 | − vq->batch_last.id = virtio32_to_cpu(vq->vq.vdev, | |
| 1007 | − vq->split.vring.used->ring[last_used_idx].id); | |
| 1008 | − vq->batch_last.len = virtio32_to_cpu(vq->vq.vdev, | |
| 1009 | − vq->split.vring.used->ring[last_used_idx].len); | |
| 1051 | + vq->batch_last.id = vring_read_split_used_id(vq, last_used_idx); | |
| 1052 | + vq->batch_last.len = vring_read_split_used_len(vq, last_used_idx); | |
| 1010 | 1053 | } |
| 1011 | 1054 | |
| 1012 | 1055 | if (vq->batch_last.id == last_used) { |
| @@ -1112,7 +1155,7 @@ static bool virtqueue_enable_cb_delayed_split(struct vring_virtqueue *vq) · 99 unmodified lines | ||
| 1112 | 1155 | &vring_used_event(&vq->split.vring), |
| 1113 | 1156 | cpu_to_virtio16(vq->vq.vdev, vq->last_used_idx + bufs)); |
| 1114 | 1157 | |
| 1115 | − if (unlikely((u16)(virtio16_to_cpu(vq->vq.vdev, vq->split.vring.used->idx) | |
| 1158 | + if (unlikely((u16)(vring_read_split_used_idx(vq) | |
| 1116 | 1159 | - vq->last_used_idx) > bufs)) { |
| 1117 | 1160 | END_USE(vq); |
| 1118 | 1161 | return false; |
| @@ -2036,10 +2079,10 @@ static void detach_buf_packed(struct vring_virtqueue *vq, · 917 unmodified lines | ||
| 2036 | 2079 | static inline bool is_used_desc_packed(const struct vring_virtqueue *vq, |
| 2037 | 2080 | u16 idx, bool used_wrap_counter) |
| 2038 | 2081 | { |
| 2039 | − bool avail, used; | |
| 2040 | 2082 | u16 flags; |
| 2083 | + bool avail, used; | |
| 2041 | 2084 | |
| 2042 | − flags = le16_to_cpu(vq->packed.vring.desc[idx].flags); | |
| 2085 | + flags = vring_read_packed_desc_flags(vq, idx); | |
| 2043 | 2086 | avail = !!(flags & (1 << VRING_PACKED_DESC_F_AVAIL)); |
| 2044 | 2087 | used = !!(flags & (1 << VRING_PACKED_DESC_F_USED)); |
| 2045 | 2088 | |
| @@ -2186,8 +2229,8 @@ static void *virtqueue_get_buf_ctx_packed(struct vring_virtqueue *vq, · 140 unmodified lines | ||
| 2186 | 2229 | last_used_idx = READ_ONCE(vq->last_used_idx); |
| 2187 | 2230 | used_wrap_counter = packed_used_wrap_counter(last_used_idx); |
| 2188 | 2231 | last_used = packed_last_used(last_used_idx); |
| 2189 | − id = le16_to_cpu(vq->packed.vring.desc[last_used].id); | |
| 2190 | − *len = le32_to_cpu(vq->packed.vring.desc[last_used].len); | |
| 2232 | + id = vring_read_packed_desc_id(vq, last_used); | |
| 2233 | + *len = vring_read_packed_desc_len(vq, last_used); | |
| 2191 | 2234 | |
| 2192 | 2235 | if (unlikely(id >= num)) { |
| 2193 | 2236 | BAD_RING(vq, "id %u out of range\n", id); |
| @@ -1257,6 +1257,15 @@ static int viortc_init_vqs(struct viortc_dev *viortc) · 1256 unmodified lines | ||
| 1257 | 1257 | return 0; |
| 1258 | 1258 | } |
| 1259 | 1259 | |
| 1260 | +static void __viortc_remove(struct viortc_dev *viortc) | |
| 1261 | +{ | |
| 1262 | + struct virtio_device *vdev = viortc->vdev; | |
| 1263 | + | |
| 1264 | + viortc_clocks_deinit(viortc); | |
| 1265 | + virtio_reset_device(vdev); | |
| 1266 | + vdev->config->del_vqs(vdev); | |
| 1267 | +} | |
| 1268 | + | |
| 1260 | 1269 | /** |
| 1261 | 1270 | * viortc_probe() - probe a virtio_rtc virtio device |
| 1262 | 1271 | * @vdev: virtio device |
| @@ -1282,7 +1291,7 @@ static int viortc_probe(struct virtio_device *vdev) · 19 unmodified lines | ||
| 1282 | 1291 | |
| 1283 | 1292 | ret = viortc_init_vqs(viortc); |
| 1284 | 1293 | if (ret) |
| 1285 | − return ret; | |
| 1294 | + goto err_reset_vdev; | |
| 1286 | 1295 | |
| 1287 | 1296 | virtio_device_ready(vdev); |
| 1288 | 1297 | |
| @@ -1329,10 +1338,7 @@ static void viortc_remove(struct virtio_device *vdev) · 40 unmodified lines | ||
| 1329 | 1338 | { |
| 1330 | 1339 | struct viortc_dev *viortc = vdev->priv; |
| 1331 | 1340 | |
| 1332 | − viortc_clocks_deinit(viortc); | |
| 1333 | − | |
| 1334 | − virtio_reset_device(vdev); | |
| 1335 | − vdev->config->del_vqs(vdev); | |
| 1341 | + __viortc_remove(viortc); | |
| 1336 | 1342 | } |
| 1337 | 1343 | |
| 1338 | 1344 | static int viortc_freeze(struct virtio_device *dev) |
| @@ -1353,9 +1359,11 @@ static int viortc_restore(struct virtio_device *dev) · 14 unmodified lines | ||
| 1353 | 1359 | bool notify = false; |
| 1354 | 1360 | int ret; |
| 1355 | 1361 | |
| 1362 | + dev->config->del_vqs(dev); | |
| 1363 | + | |
| 1356 | 1364 | ret = viortc_init_vqs(viortc); |
| 1357 | 1365 | if (ret) |
| 1358 | − return ret; | |
| 1366 | + goto err_remove; | |
| 1359 | 1367 | |
| 1360 | 1368 | alarm_viortc_vq = &viortc->vqs[VIORTC_ALARMQ]; |
| 1361 | 1369 | alarm_vq = alarm_viortc_vq->vq; |
| @@ -1364,7 +1372,7 @@ static int viortc_restore(struct virtio_device *dev) · 2 unmodified lines | ||
| 1364 | 1372 | ret = viortc_populate_vq(viortc, alarm_viortc_vq, |
| 1365 | 1373 | VIORTC_ALARMQ_BUF_CAP, false); |
| 1366 | 1374 | if (ret) |
| 1367 | − return ret; | |
| 1375 | + goto err_remove; | |
| 1368 | 1376 | |
| 1369 | 1377 | notify = virtqueue_kick_prepare(alarm_vq); |
| 1370 | 1378 | } |
| @@ -1372,8 +1380,12 @@ static int viortc_restore(struct virtio_device *dev) · 1 unmodified line | ||
| 1372 | 1380 | virtio_device_ready(dev); |
| 1373 | 1381 | |
| 1374 | 1382 | if (notify && !virtqueue_notify(alarm_vq)) |
| 1375 | − ret = -EIO; | |
| 1383 | + return -EIO; | |
| 1384 | + | |
| 1385 | + return 0; | |
| 1376 | 1386 | |
| 1387 | +err_remove: | |
| 1388 | + __viortc_remove(viortc); | |
| 1377 | 1389 | return ret; |
| 1378 | 1390 | } |
| 1379 | 1391 | |
| @@ -157,11 +157,13 @@ struct virtio_admin_cmd { · 156 unmodified lines | ||
| 157 | 157 | * @id: the device type identification (used to match it with a driver). |
| 158 | 158 | * @config: the configuration ops for this device. |
| 159 | 159 | * @vringh_config: configuration ops for host vrings. |
| 160 | + * @map: the map operations for mapping virtio device memory. | |
| 160 | 161 | * @vqs: the list of virtqueues for this device. |
| 161 | 162 | * @features: the 64 lower features supported by both driver and device. |
| 162 | 163 | * @features_array: the full features space supported by both driver and |
| 163 | 164 | * device. |
| 164 | 165 | * @priv: private pointer for the driver's use. |
| 166 | + * @vmap: the map container with transport- or device-specific metadata. | |
| 165 | 167 | * @debugfs_dir: debugfs directory entry. |
| 166 | 168 | * @debugfs_filter_features: features to be filtered set by debugfs. |
| 167 | 169 | */ |
| @@ -0,0 +1,78 @@ | ||
| 1 | +/* SPDX-License-Identifier: BSD-3-Clause */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2021-2023 OpenSynergy GmbH | |
| 4 | + * Copyright Red Hat, Inc. 2025 | |
| 5 | + */ | |
| 6 | +#ifndef _LINUX_VIRTIO_VIRTIO_CAN_H | |
| 7 | +#define _LINUX_VIRTIO_VIRTIO_CAN_H | |
| 8 | + | |
| 9 | +#include <linux/types.h> | |
| 10 | +#include <linux/virtio_types.h> | |
| 11 | +#include <linux/virtio_ids.h> | |
| 12 | +#include <linux/virtio_config.h> | |
| 13 | + | |
| 14 | +/* Feature bit numbers */ | |
| 15 | +#define VIRTIO_CAN_F_CAN_CLASSIC 0 | |
| 16 | +#define VIRTIO_CAN_F_CAN_FD 1 | |
| 17 | +#define VIRTIO_CAN_F_RTR_FRAMES 2 | |
| 18 | +#define VIRTIO_CAN_F_LATE_TX_ACK 3 | |
| 19 | + | |
| 20 | +/* CAN Result Types */ | |
| 21 | +#define VIRTIO_CAN_RESULT_OK 0 | |
| 22 | +#define VIRTIO_CAN_RESULT_NOT_OK 1 | |
| 23 | + | |
| 24 | +/* CAN flags to determine type of CAN Id */ | |
| 25 | +#define VIRTIO_CAN_FLAGS_EXTENDED 0x8000 | |
| 26 | +#define VIRTIO_CAN_FLAGS_FD 0x4000 | |
| 27 | +#define VIRTIO_CAN_FLAGS_RTR 0x2000 | |
| 28 | + | |
| 29 | +#define VIRTIO_CAN_MAX_DLEN 64 /* this is like CANFD_MAX_DLEN */ | |
| 30 | + | |
| 31 | +struct virtio_can_config { | |
| 32 | +#define VIRTIO_CAN_S_CTRL_BUSOFF (1u << 0) /* Controller BusOff */ | |
| 33 | + /* CAN controller status */ | |
| 34 | + __le16 status; | |
| 35 | +}; | |
| 36 | + | |
| 37 | +/* TX queue message types */ | |
| 38 | +struct virtio_can_tx_out { | |
| 39 | +#define VIRTIO_CAN_TX 0x0001 | |
| 40 | + __le16 msg_type; | |
| 41 | + __le16 length; /* 0..8 CC, 0..64 CAN-FD, 0..2048 CAN-XL, 12 bits */ | |
| 42 | + __u8 reserved_classic_dlc; /* If CAN classic length = 8 then DLC can be 8..15 */ | |
| 43 | + __u8 padding; | |
| 44 | + __le16 reserved_xl_priority; /* May be needed for CAN XL priority */ | |
| 45 | + __le32 flags; | |
| 46 | + __le32 can_id; | |
| 47 | + __u8 sdu[] __counted_by_le(length); | |
| 48 | +}; | |
| 49 | + | |
| 50 | +struct virtio_can_tx_in { | |
| 51 | + __u8 result; | |
| 52 | +}; | |
| 53 | + | |
| 54 | +/* RX queue message types */ | |
| 55 | +struct virtio_can_rx { | |
| 56 | +#define VIRTIO_CAN_RX 0x0101 | |
| 57 | + __le16 msg_type; | |
| 58 | + __le16 length; /* 0..8 CC, 0..64 CAN-FD, 0..2048 CAN-XL, 12 bits */ | |
| 59 | + __u8 reserved_classic_dlc; /* If CAN classic length = 8 then DLC can be 8..15 */ | |
| 60 | + __u8 padding; | |
| 61 | + __le16 reserved_xl_priority; /* May be needed for CAN XL priority */ | |
| 62 | + __le32 flags; | |
| 63 | + __le32 can_id; | |
| 64 | + __u8 sdu[] __counted_by_le(length); | |
| 65 | +}; | |
| 66 | + | |
| 67 | +/* Control queue message types */ | |
| 68 | +struct virtio_can_control_out { | |
| 69 | +#define VIRTIO_CAN_SET_CTRL_MODE_START 0x0201 | |
| 70 | +#define VIRTIO_CAN_SET_CTRL_MODE_STOP 0x0202 | |
| 71 | + __le16 msg_type; | |
| 72 | +}; | |
| 73 | + | |
| 74 | +struct virtio_can_control_in { | |
| 75 | + __u8 result; | |
| 76 | +}; | |
| 77 | + | |
| 78 | +#endif /* #ifndef _LINUX_VIRTIO_VIRTIO_CAN_H */ | |
| @@ -44,7 +44,7 @@ · 43 unmodified lines | ||
| 44 | 44 | #define VIRTIO_CONSOLE_BAD_ID (~(__u32)0) |
| 45 | 45 | |
| 46 | 46 | struct virtio_console_config { |
| 47 | − /* colums of the screens */ | |
| 47 | + /* columns of the screens */ | |
| 48 | 48 | __virtio16 cols; |
| 49 | 49 | /* rows of the screens */ |
| 50 | 50 | __virtio16 rows; |
| @@ -123,7 +123,6 @@ struct vhost_task *vhost_task_create(bool (*fn)(void *), · 122 unmodified lines | ||
| 123 | 123 | struct kernel_clone_args args = { |
| 124 | 124 | .flags = CLONE_FS | CLONE_UNTRACED | CLONE_VM | |
| 125 | 125 | CLONE_THREAD | CLONE_SIGHAND, |
| 126 | − .exit_signal = 0, | |
| 127 | 126 | .fn = vhost_task_fn, |
| 128 | 127 | .name = name, |
| 129 | 128 | .user_worker = 1, |
| @@ -60,4 +60,6 @@ enum dma_data_direction { · 59 unmodified lines | ||
| 60 | 60 | */ |
| 61 | 61 | #define DMA_MAPPING_ERROR (~(dma_addr_t)0) |
| 62 | 62 | |
| 63 | +#define DMA_ATTR_CPU_CACHE_CLEAN (1UL << 11) | |
| 64 | + | |
| 63 | 65 | #endif |
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | 2 | #ifndef ERR_H |
| 3 | 3 | #define ERR_H |
| 4 | +#include <linux/kernel.h> | |
| 4 | 5 | #define MAX_ERRNO 4095 |
| 5 | 6 | |
| 6 | 7 | #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) |
| @@ -65,6 +65,12 @@ static inline void *kmalloc_array(unsigned n, size_t s, gfp_t gfp) · 64 unmodified lines | ||
| 65 | 65 | return kmalloc(n * s, gfp); |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | +#define kmalloc_obj(VAR_OR_TYPE, ...) \ | |
| 69 | + ((typeof(VAR_OR_TYPE) *)kmalloc(sizeof(typeof(VAR_OR_TYPE)), 0)) | |
| 70 | + | |
| 71 | +#define kmalloc_objs(VAR_OR_TYPE, COUNT, ...) \ | |
| 72 | + ((typeof(VAR_OR_TYPE) *)kmalloc(sizeof(typeof(VAR_OR_TYPE)) * (COUNT), 0)) | |
| 73 | + | |
| 68 | 74 | static inline void *kzalloc(size_t s, gfp_t gfp) |
| 69 | 75 | { |
| 70 | 76 | void *p = kmalloc(s, gfp); |
| @@ -159,7 +159,12 @@ static int parallel_test(u64 features, · 158 unmodified lines | ||
| 159 | 159 | |
| 160 | 160 | /* Parent and child use separate addresses, to check our mapping logic! */ |
| 161 | 161 | host_map = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); |
| 162 | + if (host_map == MAP_FAILED) | |
| 163 | + err(1, "mmap host_map"); | |
| 164 | + | |
| 162 | 165 | guest_map = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); |
| 166 | + if (guest_map == MAP_FAILED) | |
| 167 | + err(1, "mmap guest_map"); | |
| 163 | 168 | |
| 164 | 169 | pipe_ret = pipe(to_guest); |
| 165 | 170 | assert(!pipe_ret); |