linux/drivers/vdpa/vdpa_sim/vdpa_sim_net.c
<<
>>
Prefs
   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
  32static char *macaddr;
  33module_param(macaddr, charp, 0);
  34MODULE_PARM_DESC(macaddr, "Ethernet MAC address");
  35
  36u8 macaddr_buf[ETH_ALEN];
  37
  38static struct vdpasim *vdpasim_net_dev;
  39
  40static 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
 109out:
 110        spin_unlock(&vdpasim->lock);
 111}
 112
 113static 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
 123static 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
 158put_dev:
 159        put_device(&vdpasim_net_dev->vdpa.dev);
 160out:
 161        return ret;
 162}
 163
 164static void __exit vdpasim_net_exit(void)
 165{
 166        struct vdpa_device *vdpa = &vdpasim_net_dev->vdpa;
 167
 168        vdpa_unregister_device(vdpa);
 169}
 170
 171module_init(vdpasim_net_init);
 172module_exit(vdpasim_net_exit);
 173
 174MODULE_VERSION(DRV_VERSION);
 175MODULE_LICENSE(DRV_LICENSE);
 176MODULE_AUTHOR(DRV_AUTHOR);
 177MODULE_DESCRIPTION(DRV_DESC);
 178