1*db1e8bb6SMax Gurtovoy // SPDX-License-Identifier: GPL-2.0-only 2*db1e8bb6SMax Gurtovoy /* 3*db1e8bb6SMax Gurtovoy * VDPA simulator for networking device. 4*db1e8bb6SMax Gurtovoy * 5*db1e8bb6SMax Gurtovoy * Copyright (c) 2020, Red Hat Inc. All rights reserved. 6*db1e8bb6SMax Gurtovoy * Author: Jason Wang <jasowang@redhat.com> 7*db1e8bb6SMax Gurtovoy * 8*db1e8bb6SMax Gurtovoy */ 9*db1e8bb6SMax Gurtovoy 10*db1e8bb6SMax Gurtovoy #include <linux/init.h> 11*db1e8bb6SMax Gurtovoy #include <linux/module.h> 12*db1e8bb6SMax Gurtovoy #include <linux/device.h> 13*db1e8bb6SMax Gurtovoy #include <linux/kernel.h> 14*db1e8bb6SMax Gurtovoy #include <linux/sched.h> 15*db1e8bb6SMax Gurtovoy #include <linux/etherdevice.h> 16*db1e8bb6SMax Gurtovoy #include <linux/vringh.h> 17*db1e8bb6SMax Gurtovoy #include <linux/vdpa.h> 18*db1e8bb6SMax Gurtovoy #include <uapi/linux/virtio_net.h> 19*db1e8bb6SMax Gurtovoy 20*db1e8bb6SMax Gurtovoy #include "vdpa_sim.h" 21*db1e8bb6SMax Gurtovoy 22*db1e8bb6SMax Gurtovoy #define DRV_VERSION "0.1" 23*db1e8bb6SMax Gurtovoy #define DRV_AUTHOR "Jason Wang <jasowang@redhat.com>" 24*db1e8bb6SMax Gurtovoy #define DRV_DESC "vDPA Device Simulator for networking device" 25*db1e8bb6SMax Gurtovoy #define DRV_LICENSE "GPL v2" 26*db1e8bb6SMax Gurtovoy 27*db1e8bb6SMax Gurtovoy #define VDPASIM_NET_FEATURES (VDPASIM_FEATURES | \ 28*db1e8bb6SMax Gurtovoy (1ULL << VIRTIO_NET_F_MAC)) 29*db1e8bb6SMax Gurtovoy 30*db1e8bb6SMax Gurtovoy #define VDPASIM_NET_VQ_NUM 2 31*db1e8bb6SMax Gurtovoy 32*db1e8bb6SMax Gurtovoy static char *macaddr; 33*db1e8bb6SMax Gurtovoy module_param(macaddr, charp, 0); 34*db1e8bb6SMax Gurtovoy MODULE_PARM_DESC(macaddr, "Ethernet MAC address"); 35*db1e8bb6SMax Gurtovoy 36*db1e8bb6SMax Gurtovoy u8 macaddr_buf[ETH_ALEN]; 37*db1e8bb6SMax Gurtovoy 38*db1e8bb6SMax Gurtovoy static struct vdpasim *vdpasim_net_dev; 39*db1e8bb6SMax Gurtovoy 40*db1e8bb6SMax Gurtovoy static void vdpasim_net_work(struct work_struct *work) 41*db1e8bb6SMax Gurtovoy { 42*db1e8bb6SMax Gurtovoy struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); 43*db1e8bb6SMax Gurtovoy struct vdpasim_virtqueue *txq = &vdpasim->vqs[1]; 44*db1e8bb6SMax Gurtovoy struct vdpasim_virtqueue *rxq = &vdpasim->vqs[0]; 45*db1e8bb6SMax Gurtovoy ssize_t read, write; 46*db1e8bb6SMax Gurtovoy size_t total_write; 47*db1e8bb6SMax Gurtovoy int pkts = 0; 48*db1e8bb6SMax Gurtovoy int err; 49*db1e8bb6SMax Gurtovoy 50*db1e8bb6SMax Gurtovoy spin_lock(&vdpasim->lock); 51*db1e8bb6SMax Gurtovoy 52*db1e8bb6SMax Gurtovoy if (!(vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK)) 53*db1e8bb6SMax Gurtovoy goto out; 54*db1e8bb6SMax Gurtovoy 55*db1e8bb6SMax Gurtovoy if (!txq->ready || !rxq->ready) 56*db1e8bb6SMax Gurtovoy goto out; 57*db1e8bb6SMax Gurtovoy 58*db1e8bb6SMax Gurtovoy while (true) { 59*db1e8bb6SMax Gurtovoy total_write = 0; 60*db1e8bb6SMax Gurtovoy err = vringh_getdesc_iotlb(&txq->vring, &txq->out_iov, NULL, 61*db1e8bb6SMax Gurtovoy &txq->head, GFP_ATOMIC); 62*db1e8bb6SMax Gurtovoy if (err <= 0) 63*db1e8bb6SMax Gurtovoy break; 64*db1e8bb6SMax Gurtovoy 65*db1e8bb6SMax Gurtovoy err = vringh_getdesc_iotlb(&rxq->vring, NULL, &rxq->in_iov, 66*db1e8bb6SMax Gurtovoy &rxq->head, GFP_ATOMIC); 67*db1e8bb6SMax Gurtovoy if (err <= 0) { 68*db1e8bb6SMax Gurtovoy vringh_complete_iotlb(&txq->vring, txq->head, 0); 69*db1e8bb6SMax Gurtovoy break; 70*db1e8bb6SMax Gurtovoy } 71*db1e8bb6SMax Gurtovoy 72*db1e8bb6SMax Gurtovoy while (true) { 73*db1e8bb6SMax Gurtovoy read = vringh_iov_pull_iotlb(&txq->vring, &txq->out_iov, 74*db1e8bb6SMax Gurtovoy vdpasim->buffer, 75*db1e8bb6SMax Gurtovoy PAGE_SIZE); 76*db1e8bb6SMax Gurtovoy if (read <= 0) 77*db1e8bb6SMax Gurtovoy break; 78*db1e8bb6SMax Gurtovoy 79*db1e8bb6SMax Gurtovoy write = vringh_iov_push_iotlb(&rxq->vring, &rxq->in_iov, 80*db1e8bb6SMax Gurtovoy vdpasim->buffer, read); 81*db1e8bb6SMax Gurtovoy if (write <= 0) 82*db1e8bb6SMax Gurtovoy break; 83*db1e8bb6SMax Gurtovoy 84*db1e8bb6SMax Gurtovoy total_write += write; 85*db1e8bb6SMax Gurtovoy } 86*db1e8bb6SMax Gurtovoy 87*db1e8bb6SMax Gurtovoy /* Make sure data is wrote before advancing index */ 88*db1e8bb6SMax Gurtovoy smp_wmb(); 89*db1e8bb6SMax Gurtovoy 90*db1e8bb6SMax Gurtovoy vringh_complete_iotlb(&txq->vring, txq->head, 0); 91*db1e8bb6SMax Gurtovoy vringh_complete_iotlb(&rxq->vring, rxq->head, total_write); 92*db1e8bb6SMax Gurtovoy 93*db1e8bb6SMax Gurtovoy /* Make sure used is visible before rasing the interrupt. */ 94*db1e8bb6SMax Gurtovoy smp_wmb(); 95*db1e8bb6SMax Gurtovoy 96*db1e8bb6SMax Gurtovoy local_bh_disable(); 97*db1e8bb6SMax Gurtovoy if (vringh_need_notify_iotlb(&txq->vring) > 0) 98*db1e8bb6SMax Gurtovoy vringh_notify(&txq->vring); 99*db1e8bb6SMax Gurtovoy if (vringh_need_notify_iotlb(&rxq->vring) > 0) 100*db1e8bb6SMax Gurtovoy vringh_notify(&rxq->vring); 101*db1e8bb6SMax Gurtovoy local_bh_enable(); 102*db1e8bb6SMax Gurtovoy 103*db1e8bb6SMax Gurtovoy if (++pkts > 4) { 104*db1e8bb6SMax Gurtovoy schedule_work(&vdpasim->work); 105*db1e8bb6SMax Gurtovoy goto out; 106*db1e8bb6SMax Gurtovoy } 107*db1e8bb6SMax Gurtovoy } 108*db1e8bb6SMax Gurtovoy 109*db1e8bb6SMax Gurtovoy out: 110*db1e8bb6SMax Gurtovoy spin_unlock(&vdpasim->lock); 111*db1e8bb6SMax Gurtovoy } 112*db1e8bb6SMax Gurtovoy 113*db1e8bb6SMax Gurtovoy static void vdpasim_net_get_config(struct vdpasim *vdpasim, void *config) 114*db1e8bb6SMax Gurtovoy { 115*db1e8bb6SMax Gurtovoy struct virtio_net_config *net_config = 116*db1e8bb6SMax Gurtovoy (struct virtio_net_config *)config; 117*db1e8bb6SMax Gurtovoy 118*db1e8bb6SMax Gurtovoy net_config->mtu = cpu_to_vdpasim16(vdpasim, 1500); 119*db1e8bb6SMax Gurtovoy net_config->status = cpu_to_vdpasim16(vdpasim, VIRTIO_NET_S_LINK_UP); 120*db1e8bb6SMax Gurtovoy memcpy(net_config->mac, macaddr_buf, ETH_ALEN); 121*db1e8bb6SMax Gurtovoy } 122*db1e8bb6SMax Gurtovoy 123*db1e8bb6SMax Gurtovoy static int __init vdpasim_net_init(void) 124*db1e8bb6SMax Gurtovoy { 125*db1e8bb6SMax Gurtovoy struct vdpasim_dev_attr dev_attr = {}; 126*db1e8bb6SMax Gurtovoy int ret; 127*db1e8bb6SMax Gurtovoy 128*db1e8bb6SMax Gurtovoy if (macaddr) { 129*db1e8bb6SMax Gurtovoy mac_pton(macaddr, macaddr_buf); 130*db1e8bb6SMax Gurtovoy if (!is_valid_ether_addr(macaddr_buf)) { 131*db1e8bb6SMax Gurtovoy ret = -EADDRNOTAVAIL; 132*db1e8bb6SMax Gurtovoy goto out; 133*db1e8bb6SMax Gurtovoy } 134*db1e8bb6SMax Gurtovoy } else { 135*db1e8bb6SMax Gurtovoy eth_random_addr(macaddr_buf); 136*db1e8bb6SMax Gurtovoy } 137*db1e8bb6SMax Gurtovoy 138*db1e8bb6SMax Gurtovoy dev_attr.id = VIRTIO_ID_NET; 139*db1e8bb6SMax Gurtovoy dev_attr.supported_features = VDPASIM_NET_FEATURES; 140*db1e8bb6SMax Gurtovoy dev_attr.nvqs = VDPASIM_NET_VQ_NUM; 141*db1e8bb6SMax Gurtovoy dev_attr.config_size = sizeof(struct virtio_net_config); 142*db1e8bb6SMax Gurtovoy dev_attr.get_config = vdpasim_net_get_config; 143*db1e8bb6SMax Gurtovoy dev_attr.work_fn = vdpasim_net_work; 144*db1e8bb6SMax Gurtovoy dev_attr.buffer_size = PAGE_SIZE; 145*db1e8bb6SMax Gurtovoy 146*db1e8bb6SMax Gurtovoy vdpasim_net_dev = vdpasim_create(&dev_attr); 147*db1e8bb6SMax Gurtovoy if (IS_ERR(vdpasim_net_dev)) { 148*db1e8bb6SMax Gurtovoy ret = PTR_ERR(vdpasim_net_dev); 149*db1e8bb6SMax Gurtovoy goto out; 150*db1e8bb6SMax Gurtovoy } 151*db1e8bb6SMax Gurtovoy 152*db1e8bb6SMax Gurtovoy ret = vdpa_register_device(&vdpasim_net_dev->vdpa); 153*db1e8bb6SMax Gurtovoy if (ret) 154*db1e8bb6SMax Gurtovoy goto put_dev; 155*db1e8bb6SMax Gurtovoy 156*db1e8bb6SMax Gurtovoy return 0; 157*db1e8bb6SMax Gurtovoy 158*db1e8bb6SMax Gurtovoy put_dev: 159*db1e8bb6SMax Gurtovoy put_device(&vdpasim_net_dev->vdpa.dev); 160*db1e8bb6SMax Gurtovoy out: 161*db1e8bb6SMax Gurtovoy return ret; 162*db1e8bb6SMax Gurtovoy } 163*db1e8bb6SMax Gurtovoy 164*db1e8bb6SMax Gurtovoy static void __exit vdpasim_net_exit(void) 165*db1e8bb6SMax Gurtovoy { 166*db1e8bb6SMax Gurtovoy struct vdpa_device *vdpa = &vdpasim_net_dev->vdpa; 167*db1e8bb6SMax Gurtovoy 168*db1e8bb6SMax Gurtovoy vdpa_unregister_device(vdpa); 169*db1e8bb6SMax Gurtovoy } 170*db1e8bb6SMax Gurtovoy 171*db1e8bb6SMax Gurtovoy module_init(vdpasim_net_init); 172*db1e8bb6SMax Gurtovoy module_exit(vdpasim_net_exit); 173*db1e8bb6SMax Gurtovoy 174*db1e8bb6SMax Gurtovoy MODULE_VERSION(DRV_VERSION); 175*db1e8bb6SMax Gurtovoy MODULE_LICENSE(DRV_LICENSE); 176*db1e8bb6SMax Gurtovoy MODULE_AUTHOR(DRV_AUTHOR); 177*db1e8bb6SMax Gurtovoy MODULE_DESCRIPTION(DRV_DESC); 178