Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vdpa: split vdpasim to core and net modules

Introduce new vdpa_sim_net and vdpa_sim (core) drivers. This is a
preparation for adding a vdpa simulator module for block devices.

Signed-off-by: Max Gurtovoy <mgurtovoy@nvidia.com>
[sgarzare: various cleanups/fixes]
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Link: https://lore.kernel.org/r/20201215144256.155342-19-sgarzare@redhat.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Max Gurtovoy and committed by
Michael S. Tsirkin
db1e8bb6 275900df

+298 -219
+9 -4
drivers/vdpa/Kconfig
··· 9 9 if VDPA 10 10 11 11 config VDPA_SIM 12 - tristate "vDPA device simulator" 12 + tristate "vDPA device simulator core" 13 13 depends on RUNTIME_TESTING_MENU && HAS_DMA 14 14 select DMA_OPS 15 15 select VHOST_RING 16 + help 17 + Enable this module to support vDPA device simulators. These devices 18 + are used for testing, prototyping and development of vDPA. 19 + 20 + config VDPA_SIM_NET 21 + tristate "vDPA simulator for networking device" 22 + depends on VDPA_SIM 16 23 select GENERIC_NET_UTILS 17 24 help 18 - vDPA networking device simulator which loop TX traffic back 19 - to RX. This device is used for testing, prototyping and 20 - development of vDPA. 25 + vDPA networking device simulator which loops TX traffic back to RX. 21 26 22 27 config IFCVF 23 28 tristate "Intel IFC VF vDPA driver"
+1
drivers/vdpa/vdpa_sim/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_VDPA_SIM) += vdpa_sim.o 3 + obj-$(CONFIG_VDPA_SIM_NET) += vdpa_sim_net.o
+6 -215
drivers/vdpa/vdpa_sim/vdpa_sim.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 - * VDPA networking device simulator. 3 + * VDPA device simulator core. 4 4 * 5 5 * Copyright (c) 2020, Red Hat Inc. All rights reserved. 6 6 * Author: Jason Wang <jasowang@redhat.com> ··· 14 14 #include <linux/slab.h> 15 15 #include <linux/sched.h> 16 16 #include <linux/dma-map-ops.h> 17 - #include <linux/etherdevice.h> 18 17 #include <linux/vringh.h> 19 18 #include <linux/vdpa.h> 20 - #include <linux/virtio_byteorder.h> 21 19 #include <linux/vhost_iotlb.h> 22 - #include <uapi/linux/virtio_config.h> 23 - #include <uapi/linux/virtio_net.h> 20 + 21 + #include "vdpa_sim.h" 24 22 25 23 #define DRV_VERSION "0.1" 26 24 #define DRV_AUTHOR "Jason Wang <jasowang@redhat.com>" 27 - #define DRV_DESC "vDPA Device Simulator" 25 + #define DRV_DESC "vDPA Device Simulator core" 28 26 #define DRV_LICENSE "GPL v2" 29 27 30 28 static int batch_mapping = 1; ··· 34 36 MODULE_PARM_DESC(max_iotlb_entries, 35 37 "Maximum number of iotlb entries. 0 means unlimited. (default: 2048)"); 36 38 37 - static char *macaddr; 38 - module_param(macaddr, charp, 0); 39 - MODULE_PARM_DESC(macaddr, "Ethernet MAC address"); 40 - 41 - u8 macaddr_buf[ETH_ALEN]; 42 - 43 - struct vdpasim_virtqueue { 44 - struct vringh vring; 45 - struct vringh_kiov in_iov; 46 - struct vringh_kiov out_iov; 47 - unsigned short head; 48 - bool ready; 49 - u64 desc_addr; 50 - u64 device_addr; 51 - u64 driver_addr; 52 - u32 num; 53 - void *private; 54 - irqreturn_t (*cb)(void *data); 55 - }; 56 - 57 39 #define VDPASIM_QUEUE_ALIGN PAGE_SIZE 58 40 #define VDPASIM_QUEUE_MAX 256 59 41 #define VDPASIM_VENDOR_ID 0 60 - #define VDPASIM_VQ_NUM 0x2 61 - #define VDPASIM_NAME "vdpasim-netdev" 62 - 63 - #define VDPASIM_FEATURES ((1ULL << VIRTIO_F_ANY_LAYOUT) | \ 64 - (1ULL << VIRTIO_F_VERSION_1) | \ 65 - (1ULL << VIRTIO_F_ACCESS_PLATFORM)) 66 - 67 - #define VDPASIM_NET_FEATURES (VDPASIM_FEATURES | \ 68 - (1ULL << VIRTIO_NET_F_MAC)) 69 - 70 - struct vdpasim; 71 - 72 - struct vdpasim_dev_attr { 73 - u64 supported_features; 74 - size_t config_size; 75 - size_t buffer_size; 76 - int nvqs; 77 - u32 id; 78 - 79 - work_func_t work_fn; 80 - void (*get_config)(struct vdpasim *vdpasim, void *config); 81 - void (*set_config)(struct vdpasim *vdpasim, const void *config); 82 - }; 83 - 84 - /* State of each vdpasim device */ 85 - struct vdpasim { 86 - struct vdpa_device vdpa; 87 - struct vdpasim_virtqueue *vqs; 88 - struct work_struct work; 89 - struct vdpasim_dev_attr dev_attr; 90 - /* spinlock to synchronize virtqueue state */ 91 - spinlock_t lock; 92 - /* virtio config according to device type */ 93 - void *config; 94 - struct vhost_iotlb *iommu; 95 - void *buffer; 96 - u32 status; 97 - u32 generation; 98 - u64 features; 99 - /* spinlock to synchronize iommu table */ 100 - spinlock_t iommu_lock; 101 - }; 102 - 103 - /* TODO: cross-endian support */ 104 - static inline bool vdpasim_is_little_endian(struct vdpasim *vdpasim) 105 - { 106 - return virtio_legacy_is_little_endian() || 107 - (vdpasim->features & (1ULL << VIRTIO_F_VERSION_1)); 108 - } 109 - 110 - static inline u16 vdpasim16_to_cpu(struct vdpasim *vdpasim, __virtio16 val) 111 - { 112 - return __virtio16_to_cpu(vdpasim_is_little_endian(vdpasim), val); 113 - } 114 - 115 - static inline __virtio16 cpu_to_vdpasim16(struct vdpasim *vdpasim, u16 val) 116 - { 117 - return __cpu_to_virtio16(vdpasim_is_little_endian(vdpasim), val); 118 - } 119 - 120 - static struct vdpasim *vdpasim_dev; 121 42 122 43 static struct vdpasim *vdpa_to_sim(struct vdpa_device *vdpa) 123 44 { ··· 105 188 vdpasim->features = 0; 106 189 vdpasim->status = 0; 107 190 ++vdpasim->generation; 108 - } 109 - 110 - static void vdpasim_net_work(struct work_struct *work) 111 - { 112 - struct vdpasim *vdpasim = container_of(work, struct 113 - vdpasim, work); 114 - struct vdpasim_virtqueue *txq = &vdpasim->vqs[1]; 115 - struct vdpasim_virtqueue *rxq = &vdpasim->vqs[0]; 116 - ssize_t read, write; 117 - size_t total_write; 118 - int pkts = 0; 119 - int err; 120 - 121 - spin_lock(&vdpasim->lock); 122 - 123 - if (!(vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK)) 124 - goto out; 125 - 126 - if (!txq->ready || !rxq->ready) 127 - goto out; 128 - 129 - while (true) { 130 - total_write = 0; 131 - err = vringh_getdesc_iotlb(&txq->vring, &txq->out_iov, NULL, 132 - &txq->head, GFP_ATOMIC); 133 - if (err <= 0) 134 - break; 135 - 136 - err = vringh_getdesc_iotlb(&rxq->vring, NULL, &rxq->in_iov, 137 - &rxq->head, GFP_ATOMIC); 138 - if (err <= 0) { 139 - vringh_complete_iotlb(&txq->vring, txq->head, 0); 140 - break; 141 - } 142 - 143 - while (true) { 144 - read = vringh_iov_pull_iotlb(&txq->vring, &txq->out_iov, 145 - vdpasim->buffer, 146 - PAGE_SIZE); 147 - if (read <= 0) 148 - break; 149 - 150 - write = vringh_iov_push_iotlb(&rxq->vring, &rxq->in_iov, 151 - vdpasim->buffer, read); 152 - if (write <= 0) 153 - break; 154 - 155 - total_write += write; 156 - } 157 - 158 - /* Make sure data is wrote before advancing index */ 159 - smp_wmb(); 160 - 161 - vringh_complete_iotlb(&txq->vring, txq->head, 0); 162 - vringh_complete_iotlb(&rxq->vring, rxq->head, total_write); 163 - 164 - /* Make sure used is visible before rasing the interrupt. */ 165 - smp_wmb(); 166 - 167 - local_bh_disable(); 168 - if (vringh_need_notify_iotlb(&txq->vring) > 0) 169 - vringh_notify(&txq->vring); 170 - if (vringh_need_notify_iotlb(&rxq->vring) > 0) 171 - vringh_notify(&rxq->vring); 172 - local_bh_enable(); 173 - 174 - if (++pkts > 4) { 175 - schedule_work(&vdpasim->work); 176 - goto out; 177 - } 178 - } 179 - 180 - out: 181 - spin_unlock(&vdpasim->lock); 182 191 } 183 192 184 193 static int dir_to_perm(enum dma_data_direction dir) ··· 222 379 static const struct vdpa_config_ops vdpasim_config_ops; 223 380 static const struct vdpa_config_ops vdpasim_batch_config_ops; 224 381 225 - static struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr) 382 + struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr) 226 383 { 227 384 const struct vdpa_config_ops *ops; 228 385 struct vdpasim *vdpasim; ··· 267 424 if (!vdpasim->buffer) 268 425 goto err_iommu; 269 426 270 - if (macaddr) { 271 - mac_pton(macaddr, macaddr_buf); 272 - if (!is_valid_ether_addr(macaddr_buf)) { 273 - ret = -EADDRNOTAVAIL; 274 - goto err_iommu; 275 - } 276 - } else { 277 - eth_random_addr(macaddr_buf); 278 - } 279 - 280 427 for (i = 0; i < dev_attr->nvqs; i++) 281 428 vringh_set_iotlb(&vdpasim->vqs[i].vring, vdpasim->iommu); 282 429 283 430 vdpasim->vdpa.dma_dev = dev; 284 - ret = vdpa_register_device(&vdpasim->vdpa); 285 - if (ret) 286 - goto err_iommu; 287 431 288 432 return vdpasim; 289 433 ··· 279 449 err_alloc: 280 450 return ERR_PTR(ret); 281 451 } 452 + EXPORT_SYMBOL_GPL(vdpasim_create); 282 453 283 454 static int vdpasim_set_vq_address(struct vdpa_device *vdpa, u16 idx, 284 455 u64 desc_area, u64 driver_area, ··· 599 768 .set_map = vdpasim_set_map, 600 769 .free = vdpasim_free, 601 770 }; 602 - 603 - static void vdpasim_net_get_config(struct vdpasim *vdpasim, void *config) 604 - { 605 - struct virtio_net_config *net_config = 606 - (struct virtio_net_config *)config; 607 - 608 - net_config->mtu = cpu_to_vdpasim16(vdpasim, 1500); 609 - net_config->status = cpu_to_vdpasim16(vdpasim, VIRTIO_NET_S_LINK_UP); 610 - memcpy(net_config->mac, macaddr_buf, ETH_ALEN); 611 - } 612 - 613 - static int __init vdpasim_dev_init(void) 614 - { 615 - struct vdpasim_dev_attr dev_attr = {}; 616 - 617 - dev_attr.id = VIRTIO_ID_NET; 618 - dev_attr.supported_features = VDPASIM_NET_FEATURES; 619 - dev_attr.nvqs = VDPASIM_VQ_NUM; 620 - dev_attr.config_size = sizeof(struct virtio_net_config); 621 - dev_attr.get_config = vdpasim_net_get_config; 622 - dev_attr.work_fn = vdpasim_net_work; 623 - dev_attr.buffer_size = PAGE_SIZE; 624 - 625 - vdpasim_dev = vdpasim_create(&dev_attr); 626 - 627 - if (!IS_ERR(vdpasim_dev)) 628 - return 0; 629 - 630 - return PTR_ERR(vdpasim_dev); 631 - } 632 - 633 - static void __exit vdpasim_dev_exit(void) 634 - { 635 - struct vdpa_device *vdpa = &vdpasim_dev->vdpa; 636 - 637 - vdpa_unregister_device(vdpa); 638 - } 639 - 640 - module_init(vdpasim_dev_init) 641 - module_exit(vdpasim_dev_exit) 642 771 643 772 MODULE_VERSION(DRV_VERSION); 644 773 MODULE_LICENSE(DRV_LICENSE);
+105
drivers/vdpa/vdpa_sim/vdpa_sim.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2020, Red Hat Inc. All rights reserved. 4 + */ 5 + 6 + #ifndef _VDPA_SIM_H 7 + #define _VDPA_SIM_H 8 + 9 + #include <linux/vringh.h> 10 + #include <linux/vdpa.h> 11 + #include <linux/virtio_byteorder.h> 12 + #include <linux/vhost_iotlb.h> 13 + #include <uapi/linux/virtio_config.h> 14 + 15 + #define VDPASIM_FEATURES ((1ULL << VIRTIO_F_ANY_LAYOUT) | \ 16 + (1ULL << VIRTIO_F_VERSION_1) | \ 17 + (1ULL << VIRTIO_F_ACCESS_PLATFORM)) 18 + 19 + struct vdpasim; 20 + 21 + struct vdpasim_virtqueue { 22 + struct vringh vring; 23 + struct vringh_kiov in_iov; 24 + struct vringh_kiov out_iov; 25 + unsigned short head; 26 + bool ready; 27 + u64 desc_addr; 28 + u64 device_addr; 29 + u64 driver_addr; 30 + u32 num; 31 + void *private; 32 + irqreturn_t (*cb)(void *data); 33 + }; 34 + 35 + struct vdpasim_dev_attr { 36 + u64 supported_features; 37 + size_t config_size; 38 + size_t buffer_size; 39 + int nvqs; 40 + u32 id; 41 + 42 + work_func_t work_fn; 43 + void (*get_config)(struct vdpasim *vdpasim, void *config); 44 + void (*set_config)(struct vdpasim *vdpasim, const void *config); 45 + }; 46 + 47 + /* State of each vdpasim device */ 48 + struct vdpasim { 49 + struct vdpa_device vdpa; 50 + struct vdpasim_virtqueue *vqs; 51 + struct work_struct work; 52 + struct vdpasim_dev_attr dev_attr; 53 + /* spinlock to synchronize virtqueue state */ 54 + spinlock_t lock; 55 + /* virtio config according to device type */ 56 + void *config; 57 + struct vhost_iotlb *iommu; 58 + void *buffer; 59 + u32 status; 60 + u32 generation; 61 + u64 features; 62 + /* spinlock to synchronize iommu table */ 63 + spinlock_t iommu_lock; 64 + }; 65 + 66 + struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *attr); 67 + 68 + /* TODO: cross-endian support */ 69 + static inline bool vdpasim_is_little_endian(struct vdpasim *vdpasim) 70 + { 71 + return virtio_legacy_is_little_endian() || 72 + (vdpasim->features & (1ULL << VIRTIO_F_VERSION_1)); 73 + } 74 + 75 + static inline u16 vdpasim16_to_cpu(struct vdpasim *vdpasim, __virtio16 val) 76 + { 77 + return __virtio16_to_cpu(vdpasim_is_little_endian(vdpasim), val); 78 + } 79 + 80 + static inline __virtio16 cpu_to_vdpasim16(struct vdpasim *vdpasim, u16 val) 81 + { 82 + return __cpu_to_virtio16(vdpasim_is_little_endian(vdpasim), val); 83 + } 84 + 85 + static inline u32 vdpasim32_to_cpu(struct vdpasim *vdpasim, __virtio32 val) 86 + { 87 + return __virtio32_to_cpu(vdpasim_is_little_endian(vdpasim), val); 88 + } 89 + 90 + static inline __virtio32 cpu_to_vdpasim32(struct vdpasim *vdpasim, u32 val) 91 + { 92 + return __cpu_to_virtio32(vdpasim_is_little_endian(vdpasim), val); 93 + } 94 + 95 + static inline u64 vdpasim64_to_cpu(struct vdpasim *vdpasim, __virtio64 val) 96 + { 97 + return __virtio64_to_cpu(vdpasim_is_little_endian(vdpasim), val); 98 + } 99 + 100 + static inline __virtio64 cpu_to_vdpasim64(struct vdpasim *vdpasim, u64 val) 101 + { 102 + return __cpu_to_virtio64(vdpasim_is_little_endian(vdpasim), val); 103 + } 104 + 105 + #endif
+177
drivers/vdpa/vdpa_sim/vdpa_sim_net.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * VDPA simulator for networking device. 4 + * 5 + * Copyright (c) 2020, Red Hat Inc. All rights reserved. 6 + * Author: Jason Wang <jasowang@redhat.com> 7 + * 8 + */ 9 + 10 + #include <linux/init.h> 11 + #include <linux/module.h> 12 + #include <linux/device.h> 13 + #include <linux/kernel.h> 14 + #include <linux/sched.h> 15 + #include <linux/etherdevice.h> 16 + #include <linux/vringh.h> 17 + #include <linux/vdpa.h> 18 + #include <uapi/linux/virtio_net.h> 19 + 20 + #include "vdpa_sim.h" 21 + 22 + #define DRV_VERSION "0.1" 23 + #define DRV_AUTHOR "Jason Wang <jasowang@redhat.com>" 24 + #define DRV_DESC "vDPA Device Simulator for networking device" 25 + #define DRV_LICENSE "GPL v2" 26 + 27 + #define VDPASIM_NET_FEATURES (VDPASIM_FEATURES | \ 28 + (1ULL << VIRTIO_NET_F_MAC)) 29 + 30 + #define VDPASIM_NET_VQ_NUM 2 31 + 32 + static char *macaddr; 33 + module_param(macaddr, charp, 0); 34 + MODULE_PARM_DESC(macaddr, "Ethernet MAC address"); 35 + 36 + u8 macaddr_buf[ETH_ALEN]; 37 + 38 + static struct vdpasim *vdpasim_net_dev; 39 + 40 + static void vdpasim_net_work(struct work_struct *work) 41 + { 42 + struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); 43 + struct vdpasim_virtqueue *txq = &vdpasim->vqs[1]; 44 + struct vdpasim_virtqueue *rxq = &vdpasim->vqs[0]; 45 + ssize_t read, write; 46 + size_t total_write; 47 + int pkts = 0; 48 + int err; 49 + 50 + spin_lock(&vdpasim->lock); 51 + 52 + if (!(vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK)) 53 + goto out; 54 + 55 + if (!txq->ready || !rxq->ready) 56 + goto out; 57 + 58 + while (true) { 59 + total_write = 0; 60 + err = vringh_getdesc_iotlb(&txq->vring, &txq->out_iov, NULL, 61 + &txq->head, GFP_ATOMIC); 62 + if (err <= 0) 63 + break; 64 + 65 + err = vringh_getdesc_iotlb(&rxq->vring, NULL, &rxq->in_iov, 66 + &rxq->head, GFP_ATOMIC); 67 + if (err <= 0) { 68 + vringh_complete_iotlb(&txq->vring, txq->head, 0); 69 + break; 70 + } 71 + 72 + while (true) { 73 + read = vringh_iov_pull_iotlb(&txq->vring, &txq->out_iov, 74 + vdpasim->buffer, 75 + PAGE_SIZE); 76 + if (read <= 0) 77 + break; 78 + 79 + write = vringh_iov_push_iotlb(&rxq->vring, &rxq->in_iov, 80 + vdpasim->buffer, read); 81 + if (write <= 0) 82 + break; 83 + 84 + total_write += write; 85 + } 86 + 87 + /* Make sure data is wrote before advancing index */ 88 + smp_wmb(); 89 + 90 + vringh_complete_iotlb(&txq->vring, txq->head, 0); 91 + vringh_complete_iotlb(&rxq->vring, rxq->head, total_write); 92 + 93 + /* Make sure used is visible before rasing the interrupt. */ 94 + smp_wmb(); 95 + 96 + local_bh_disable(); 97 + if (vringh_need_notify_iotlb(&txq->vring) > 0) 98 + vringh_notify(&txq->vring); 99 + if (vringh_need_notify_iotlb(&rxq->vring) > 0) 100 + vringh_notify(&rxq->vring); 101 + local_bh_enable(); 102 + 103 + if (++pkts > 4) { 104 + schedule_work(&vdpasim->work); 105 + goto out; 106 + } 107 + } 108 + 109 + out: 110 + spin_unlock(&vdpasim->lock); 111 + } 112 + 113 + static void vdpasim_net_get_config(struct vdpasim *vdpasim, void *config) 114 + { 115 + struct virtio_net_config *net_config = 116 + (struct virtio_net_config *)config; 117 + 118 + net_config->mtu = cpu_to_vdpasim16(vdpasim, 1500); 119 + net_config->status = cpu_to_vdpasim16(vdpasim, VIRTIO_NET_S_LINK_UP); 120 + memcpy(net_config->mac, macaddr_buf, ETH_ALEN); 121 + } 122 + 123 + static int __init vdpasim_net_init(void) 124 + { 125 + struct vdpasim_dev_attr dev_attr = {}; 126 + int ret; 127 + 128 + if (macaddr) { 129 + mac_pton(macaddr, macaddr_buf); 130 + if (!is_valid_ether_addr(macaddr_buf)) { 131 + ret = -EADDRNOTAVAIL; 132 + goto out; 133 + } 134 + } else { 135 + eth_random_addr(macaddr_buf); 136 + } 137 + 138 + dev_attr.id = VIRTIO_ID_NET; 139 + dev_attr.supported_features = VDPASIM_NET_FEATURES; 140 + dev_attr.nvqs = VDPASIM_NET_VQ_NUM; 141 + dev_attr.config_size = sizeof(struct virtio_net_config); 142 + dev_attr.get_config = vdpasim_net_get_config; 143 + dev_attr.work_fn = vdpasim_net_work; 144 + dev_attr.buffer_size = PAGE_SIZE; 145 + 146 + vdpasim_net_dev = vdpasim_create(&dev_attr); 147 + if (IS_ERR(vdpasim_net_dev)) { 148 + ret = PTR_ERR(vdpasim_net_dev); 149 + goto out; 150 + } 151 + 152 + ret = vdpa_register_device(&vdpasim_net_dev->vdpa); 153 + if (ret) 154 + goto put_dev; 155 + 156 + return 0; 157 + 158 + put_dev: 159 + put_device(&vdpasim_net_dev->vdpa.dev); 160 + out: 161 + return ret; 162 + } 163 + 164 + static void __exit vdpasim_net_exit(void) 165 + { 166 + struct vdpa_device *vdpa = &vdpasim_net_dev->vdpa; 167 + 168 + vdpa_unregister_device(vdpa); 169 + } 170 + 171 + module_init(vdpasim_net_init); 172 + module_exit(vdpasim_net_exit); 173 + 174 + MODULE_VERSION(DRV_VERSION); 175 + MODULE_LICENSE(DRV_LICENSE); 176 + MODULE_AUTHOR(DRV_AUTHOR); 177 + MODULE_DESCRIPTION(DRV_DESC);