]> Git Repo - linux.git/commitdiff
Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
authorLinus Torvalds <[email protected]>
Thu, 31 Mar 2022 20:57:15 +0000 (13:57 -0700)
committerLinus Torvalds <[email protected]>
Thu, 31 Mar 2022 20:57:15 +0000 (13:57 -0700)
Pull virtio updates from Michael Tsirkin:

 - vdpa generic device type support

 - more virtio hardening for broken devices (but on the same theme,
   revert some virtio hotplug hardening patches - they were misusing
   some interrupt flags and had to be reverted)

 - RSS support in virtio-net

 - max device MTU support in mlx5 vdpa

 - akcipher support in virtio-crypto

 - shared IRQ support in ifcvf vdpa

 - a minor performance improvement in vhost

 - enable virtio mem for ARM64

 - beginnings of advance dma support

 - cleanups, fixes all over the place

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (33 commits)
  vdpa/mlx5: Avoid processing works if workqueue was destroyed
  vhost: handle error while adding split ranges to iotlb
  vdpa: support exposing the count of vqs to userspace
  vdpa: change the type of nvqs to u32
  vdpa: support exposing the config size to userspace
  vdpa/mlx5: re-create forwarding rules after mac modified
  virtio: pci: check bar values read from virtio config space
  Revert "virtio_pci: harden MSI-X interrupts"
  Revert "virtio-pci: harden INTX interrupts"
  drivers/net/virtio_net: Added RSS hash report control.
  drivers/net/virtio_net: Added RSS hash report.
  drivers/net/virtio_net: Added basic RSS support.
  drivers/net/virtio_net: Fixed padded vheader to use v1 with hash.
  virtio: use virtio_device_ready() in virtio_device_restore()
  tools/virtio: compile with -pthread
  tools/virtio: fix after premapped buf support
  virtio_ring: remove flags check for unmap packed indirect desc
  virtio_ring: remove flags check for unmap split indirect desc
  virtio_ring: rename vring_unmap_state_packed() to vring_unmap_extra_packed()
  net/mlx5: Add support for configuring max device MTU
  ...

1  2 
drivers/net/virtio_net.c

diff --combined drivers/net/virtio_net.c
index 11f26b00a2262bc7e263d1b884d38b4899135204,17eeb4f807e36de455e389e8c6c9e52d367e132a..87838cbe38cf6cced970ea075b328c511fc0a6dd
@@@ -169,6 -169,24 +169,24 @@@ struct receive_queue 
        struct xdp_rxq_info xdp_rxq;
  };
  
+ /* This structure can contain rss message with maximum settings for indirection table and keysize
+  * Note, that default structure that describes RSS configuration virtio_net_rss_config
+  * contains same info but can't handle table values.
+  * In any case, structure would be passed to virtio hw through sg_buf split by parts
+  * because table sizes may be differ according to the device configuration.
+  */
+ #define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
+ #define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
+ struct virtio_net_ctrl_rss {
+       u32 hash_types;
+       u16 indirection_table_mask;
+       u16 unclassified_queue;
+       u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
+       u16 max_tx_vq;
+       u8 hash_key_length;
+       u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+ };
  /* Control VQ buffers: protected by the rtnl lock */
  struct control_buf {
        struct virtio_net_ctrl_hdr hdr;
        u8 allmulti;
        __virtio16 vid;
        __virtio64 offloads;
+       struct virtio_net_ctrl_rss rss;
  };
  
  struct virtnet_info {
        /* Host will merge rx buffers for big packets (shake it! shake it!) */
        bool mergeable_rx_bufs;
  
+       /* Host supports rss and/or hash report */
+       bool has_rss;
+       bool has_rss_hash_report;
+       u8 rss_key_size;
+       u16 rss_indir_table_size;
+       u32 rss_hash_types_supported;
+       u32 rss_hash_types_saved;
        /* Has control virtqueue */
        bool has_cvq;
  
  };
  
  struct padded_vnet_hdr {
-       struct virtio_net_hdr_mrg_rxbuf hdr;
+       struct virtio_net_hdr_v1_hash hdr;
        /*
         * hdr is in a separate sg buffer, and data sg buffer shares same page
         * with this header sg. This padding makes next sg 16 byte aligned
         * after the header.
         */
-       char padding[4];
+       char padding[12];
  };
  
  static bool is_xdp_frame(void *ptr)
@@@ -396,7 -423,7 +423,7 @@@ static struct sk_buff *page_to_skb(stru
  
        hdr_len = vi->hdr_len;
        if (vi->mergeable_rx_bufs)
-               hdr_padded_len = sizeof(*hdr);
+               hdr_padded_len = hdr_len;
        else
                hdr_padded_len = sizeof(struct padded_vnet_hdr);
  
@@@ -1123,6 -1150,35 +1150,35 @@@ xdp_xmit
        return NULL;
  }
  
+ static void virtio_skb_set_hash(const struct virtio_net_hdr_v1_hash *hdr_hash,
+                               struct sk_buff *skb)
+ {
+       enum pkt_hash_types rss_hash_type;
+       if (!hdr_hash || !skb)
+               return;
+       switch ((int)hdr_hash->hash_report) {
+       case VIRTIO_NET_HASH_REPORT_TCPv4:
+       case VIRTIO_NET_HASH_REPORT_UDPv4:
+       case VIRTIO_NET_HASH_REPORT_TCPv6:
+       case VIRTIO_NET_HASH_REPORT_UDPv6:
+       case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
+       case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
+               rss_hash_type = PKT_HASH_TYPE_L4;
+               break;
+       case VIRTIO_NET_HASH_REPORT_IPv4:
+       case VIRTIO_NET_HASH_REPORT_IPv6:
+       case VIRTIO_NET_HASH_REPORT_IPv6_EX:
+               rss_hash_type = PKT_HASH_TYPE_L3;
+               break;
+       case VIRTIO_NET_HASH_REPORT_NONE:
+       default:
+               rss_hash_type = PKT_HASH_TYPE_NONE;
+       }
+       skb_set_hash(skb, (unsigned int)hdr_hash->hash_value, rss_hash_type);
+ }
  static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
                        void *buf, unsigned int len, void **ctx,
                        unsigned int *xdp_xmit,
                return;
  
        hdr = skb_vnet_hdr(skb);
+       if (dev->features & NETIF_F_RXHASH && vi->has_rss_hash_report)
+               virtio_skb_set_hash((const struct virtio_net_hdr_v1_hash *)hdr, skb);
  
        if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
@@@ -1266,7 -1324,8 +1324,8 @@@ static unsigned int get_mergeable_buf_l
                                          struct ewma_pkt_len *avg_pkt_len,
                                          unsigned int room)
  {
-       const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+       struct virtnet_info *vi = rq->vq->vdev->priv;
+       const size_t hdr_len = vi->hdr_len;
        unsigned int len;
  
        if (room)
@@@ -2183,6 -2242,174 +2242,174 @@@ static void virtnet_get_ringparam(struc
        ring->tx_pending = ring->tx_max_pending;
  }
  
+ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+ {
+       struct net_device *dev = vi->dev;
+       struct scatterlist sgs[4];
+       unsigned int sg_buf_size;
+       /* prepare sgs */
+       sg_init_table(sgs, 4);
+       sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
+       sg_set_buf(&sgs[0], &vi->ctrl->rss, sg_buf_size);
+       sg_buf_size = sizeof(uint16_t) * (vi->ctrl->rss.indirection_table_mask + 1);
+       sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
+       sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
+                       - offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
+       sg_set_buf(&sgs[2], &vi->ctrl->rss.max_tx_vq, sg_buf_size);
+       sg_buf_size = vi->rss_key_size;
+       sg_set_buf(&sgs[3], vi->ctrl->rss.key, sg_buf_size);
+       if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
+                                 vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG
+                                 : VIRTIO_NET_CTRL_MQ_HASH_CONFIG, sgs)) {
+               dev_warn(&dev->dev, "VIRTIONET issue with committing RSS sgs\n");
+               return false;
+       }
+       return true;
+ }
+ static void virtnet_init_default_rss(struct virtnet_info *vi)
+ {
+       u32 indir_val = 0;
+       int i = 0;
+       vi->ctrl->rss.hash_types = vi->rss_hash_types_supported;
+       vi->rss_hash_types_saved = vi->rss_hash_types_supported;
+       vi->ctrl->rss.indirection_table_mask = vi->rss_indir_table_size
+                                               ? vi->rss_indir_table_size - 1 : 0;
+       vi->ctrl->rss.unclassified_queue = 0;
+       for (; i < vi->rss_indir_table_size; ++i) {
+               indir_val = ethtool_rxfh_indir_default(i, vi->curr_queue_pairs);
+               vi->ctrl->rss.indirection_table[i] = indir_val;
+       }
+       vi->ctrl->rss.max_tx_vq = vi->curr_queue_pairs;
+       vi->ctrl->rss.hash_key_length = vi->rss_key_size;
+       netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
+ }
+ static void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info)
+ {
+       info->data = 0;
+       switch (info->flow_type) {
+       case TCP_V4_FLOW:
+               if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv4) {
+                       info->data = RXH_IP_SRC | RXH_IP_DST |
+                                                RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               } else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
+                       info->data = RXH_IP_SRC | RXH_IP_DST;
+               }
+               break;
+       case TCP_V6_FLOW:
+               if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv6) {
+                       info->data = RXH_IP_SRC | RXH_IP_DST |
+                                                RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               } else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
+                       info->data = RXH_IP_SRC | RXH_IP_DST;
+               }
+               break;
+       case UDP_V4_FLOW:
+               if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv4) {
+                       info->data = RXH_IP_SRC | RXH_IP_DST |
+                                                RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               } else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
+                       info->data = RXH_IP_SRC | RXH_IP_DST;
+               }
+               break;
+       case UDP_V6_FLOW:
+               if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv6) {
+                       info->data = RXH_IP_SRC | RXH_IP_DST |
+                                                RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               } else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
+                       info->data = RXH_IP_SRC | RXH_IP_DST;
+               }
+               break;
+       case IPV4_FLOW:
+               if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4)
+                       info->data = RXH_IP_SRC | RXH_IP_DST;
+               break;
+       case IPV6_FLOW:
+               if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6)
+                       info->data = RXH_IP_SRC | RXH_IP_DST;
+               break;
+       default:
+               info->data = 0;
+               break;
+       }
+ }
+ static bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *info)
+ {
+       u32 new_hashtypes = vi->rss_hash_types_saved;
+       bool is_disable = info->data & RXH_DISCARD;
+       bool is_l4 = info->data == (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3);
+       /* supports only 'sd', 'sdfn' and 'r' */
+       if (!((info->data == (RXH_IP_SRC | RXH_IP_DST)) | is_l4 | is_disable))
+               return false;
+       switch (info->flow_type) {
+       case TCP_V4_FLOW:
+               new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv4 | VIRTIO_NET_RSS_HASH_TYPE_TCPv4);
+               if (!is_disable)
+                       new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv4
+                               | (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_TCPv4 : 0);
+               break;
+       case UDP_V4_FLOW:
+               new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv4 | VIRTIO_NET_RSS_HASH_TYPE_UDPv4);
+               if (!is_disable)
+                       new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv4
+                               | (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_UDPv4 : 0);
+               break;
+       case IPV4_FLOW:
+               new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv4;
+               if (!is_disable)
+                       new_hashtypes = VIRTIO_NET_RSS_HASH_TYPE_IPv4;
+               break;
+       case TCP_V6_FLOW:
+               new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv6 | VIRTIO_NET_RSS_HASH_TYPE_TCPv6);
+               if (!is_disable)
+                       new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv6
+                               | (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_TCPv6 : 0);
+               break;
+       case UDP_V6_FLOW:
+               new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv6 | VIRTIO_NET_RSS_HASH_TYPE_UDPv6);
+               if (!is_disable)
+                       new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv6
+                               | (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_UDPv6 : 0);
+               break;
+       case IPV6_FLOW:
+               new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv6;
+               if (!is_disable)
+                       new_hashtypes = VIRTIO_NET_RSS_HASH_TYPE_IPv6;
+               break;
+       default:
+               /* unsupported flow */
+               return false;
+       }
+       /* if unsupported hashtype was set */
+       if (new_hashtypes != (new_hashtypes & vi->rss_hash_types_supported))
+               return false;
+       if (new_hashtypes != vi->rss_hash_types_saved) {
+               vi->rss_hash_types_saved = new_hashtypes;
+               vi->ctrl->rss.hash_types = vi->rss_hash_types_saved;
+               if (vi->dev->features & NETIF_F_RXHASH)
+                       return virtnet_commit_rss_command(vi);
+       }
+       return true;
+ }
  
  static void virtnet_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
@@@ -2411,6 -2638,92 +2638,92 @@@ static void virtnet_update_settings(str
                vi->duplex = duplex;
  }
  
+ static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
+ {
+       return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
+ }
+ static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
+ {
+       return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
+ }
+ static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
+ {
+       struct virtnet_info *vi = netdev_priv(dev);
+       int i;
+       if (indir) {
+               for (i = 0; i < vi->rss_indir_table_size; ++i)
+                       indir[i] = vi->ctrl->rss.indirection_table[i];
+       }
+       if (key)
+               memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
+       if (hfunc)
+               *hfunc = ETH_RSS_HASH_TOP;
+       return 0;
+ }
+ static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
+ {
+       struct virtnet_info *vi = netdev_priv(dev);
+       int i;
+       if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+               return -EOPNOTSUPP;
+       if (indir) {
+               for (i = 0; i < vi->rss_indir_table_size; ++i)
+                       vi->ctrl->rss.indirection_table[i] = indir[i];
+       }
+       if (key)
+               memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
+       virtnet_commit_rss_command(vi);
+       return 0;
+ }
+ static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
+ {
+       struct virtnet_info *vi = netdev_priv(dev);
+       int rc = 0;
+       switch (info->cmd) {
+       case ETHTOOL_GRXRINGS:
+               info->data = vi->curr_queue_pairs;
+               break;
+       case ETHTOOL_GRXFH:
+               virtnet_get_hashflow(vi, info);
+               break;
+       default:
+               rc = -EOPNOTSUPP;
+       }
+       return rc;
+ }
+ static int virtnet_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
+ {
+       struct virtnet_info *vi = netdev_priv(dev);
+       int rc = 0;
+       switch (info->cmd) {
+       case ETHTOOL_SRXFH:
+               if (!virtnet_set_hashflow(vi, info))
+                       rc = -EINVAL;
+               break;
+       default:
+               rc = -EOPNOTSUPP;
+       }
+       return rc;
+ }
  static const struct ethtool_ops virtnet_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
        .get_drvinfo = virtnet_get_drvinfo,
        .set_link_ksettings = virtnet_set_link_ksettings,
        .set_coalesce = virtnet_set_coalesce,
        .get_coalesce = virtnet_get_coalesce,
+       .get_rxfh_key_size = virtnet_get_rxfh_key_size,
+       .get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
+       .get_rxfh = virtnet_get_rxfh,
+       .set_rxfh = virtnet_set_rxfh,
+       .get_rxnfc = virtnet_get_rxnfc,
+       .set_rxnfc = virtnet_set_rxnfc,
  };
  
  static void virtnet_freeze_down(struct virtio_device *vdev)
@@@ -2678,6 -2997,16 +2997,16 @@@ static int virtnet_set_features(struct 
                vi->guest_offloads = offloads;
        }
  
+       if ((dev->features ^ features) & NETIF_F_RXHASH) {
+               if (features & NETIF_F_RXHASH)
+                       vi->ctrl->rss.hash_types = vi->rss_hash_types_saved;
+               else
+                       vi->ctrl->rss.hash_types = VIRTIO_NET_HASH_REPORT_NONE;
+               if (!virtnet_commit_rss_command(vi))
+                       return -EINVAL;
+       }
        return 0;
  }
  
@@@ -2851,7 -3180,7 +3180,7 @@@ static void virtnet_del_vqs(struct virt
   */
  static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqueue *vq)
  {
-       const unsigned int hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+       const unsigned int hdr_len = vi->hdr_len;
        unsigned int rq_size = virtqueue_get_vring_size(vq);
        unsigned int packet_len = vi->big_packets ? IP_MAX_MTU : vi->dev->max_mtu;
        unsigned int buf_len = hdr_len + ETH_HLEN + VLAN_HLEN + packet_len;
@@@ -3072,6 -3401,10 +3401,10 @@@ static bool virtnet_validate_features(s
                             "VIRTIO_NET_F_CTRL_VQ") ||
             VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
             VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
+                            "VIRTIO_NET_F_CTRL_VQ") ||
+            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS,
+                            "VIRTIO_NET_F_CTRL_VQ") ||
+            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
                             "VIRTIO_NET_F_CTRL_VQ"))) {
                return false;
        }
@@@ -3112,13 -3445,14 +3445,14 @@@ static int virtnet_probe(struct virtio_
        u16 max_queue_pairs;
        int mtu;
  
-       /* Find if host supports multiqueue virtio_net device */
-       err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
-                                  struct virtio_net_config,
-                                  max_virtqueue_pairs, &max_queue_pairs);
+       /* Find if host supports multiqueue/rss virtio_net device */
+       max_queue_pairs = 1;
+       if (virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
+               max_queue_pairs =
+                    virtio_cread16(vdev, offsetof(struct virtio_net_config, max_virtqueue_pairs));
  
        /* We need at least 2 queue's */
-       if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
+       if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
            max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
            !virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
                max_queue_pairs = 1;
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
                vi->mergeable_rx_bufs = true;
  
-       if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
-           virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
+       if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT))
+               vi->has_rss_hash_report = true;
+       if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
+               vi->has_rss = true;
+       if (vi->has_rss || vi->has_rss_hash_report) {
+               vi->rss_indir_table_size =
+                       virtio_cread16(vdev, offsetof(struct virtio_net_config,
+                               rss_max_indirection_table_length));
+               vi->rss_key_size =
+                       virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
+               vi->rss_hash_types_supported =
+                   virtio_cread32(vdev, offsetof(struct virtio_net_config, supported_hash_types));
+               vi->rss_hash_types_supported &=
+                               ~(VIRTIO_NET_RSS_HASH_TYPE_IP_EX |
+                                 VIRTIO_NET_RSS_HASH_TYPE_TCP_EX |
+                                 VIRTIO_NET_RSS_HASH_TYPE_UDP_EX);
+               dev->hw_features |= NETIF_F_RXHASH;
+       }
+       if (vi->has_rss_hash_report)
+               vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash);
+       else if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
+                virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
                vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
        else
                vi->hdr_len = sizeof(struct virtio_net_hdr);
                }
        }
  
+       if (vi->has_rss || vi->has_rss_hash_report)
+               virtnet_init_default_rss(vi);
        err = register_netdev(dev);
        if (err) {
                pr_debug("virtio_net: registering device failed\n");
@@@ -3405,7 -3767,8 +3767,8 @@@ static struct virtio_device_id id_table
        VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
        VIRTIO_NET_F_CTRL_MAC_ADDR, \
        VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
-       VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY
+       VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \
+       VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT
  
  static unsigned int features[] = {
        VIRTNET_FEATURES,
@@@ -3449,7 -3812,8 +3812,7 @@@ static __init int virtio_net_driver_ini
                                      NULL, virtnet_cpu_dead);
        if (ret)
                goto err_dead;
 -
 -        ret = register_virtio_driver(&virtio_net_driver);
 +      ret = register_virtio_driver(&virtio_net_driver);
        if (ret)
                goto err_virtio;
        return 0;
This page took 0.164545 seconds and 4 git commands to generate.