@@ -169,6 +169,24 @@ struct receive_queue {
169169 struct xdp_rxq_info xdp_rxq ;
170170};
171171
172+ /* This structure can contain rss message with maximum settings for indirection table and keysize
173+ * Note, that default structure that describes RSS configuration virtio_net_rss_config
174+ * contains same info but can't handle table values.
175+ * In any case, structure would be passed to virtio hw through sg_buf split by parts
176+ * because table sizes may be differ according to the device configuration.
177+ */
178+ #define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
179+ #define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
180+ struct virtio_net_ctrl_rss {
181+ u32 hash_types ;
182+ u16 indirection_table_mask ;
183+ u16 unclassified_queue ;
184+ u16 indirection_table [VIRTIO_NET_RSS_MAX_TABLE_LEN ];
185+ u16 max_tx_vq ;
186+ u8 hash_key_length ;
187+ u8 key [VIRTIO_NET_RSS_MAX_KEY_SIZE ];
188+ };
189+
172190/* Control VQ buffers: protected by the rtnl lock */
173191struct control_buf {
174192 struct virtio_net_ctrl_hdr hdr ;
@@ -178,6 +196,7 @@ struct control_buf {
178196 u8 allmulti ;
179197 __virtio16 vid ;
180198 __virtio64 offloads ;
199+ struct virtio_net_ctrl_rss rss ;
181200};
182201
183202struct virtnet_info {
@@ -206,6 +225,12 @@ struct virtnet_info {
206225 /* Host will merge rx buffers for big packets (shake it! shake it!) */
207226 bool mergeable_rx_bufs ;
208227
228+ /* Host supports rss and/or hash report */
229+ bool has_rss ;
230+ u8 rss_key_size ;
231+ u16 rss_indir_table_size ;
232+ u32 rss_hash_types_supported ;
233+
209234 /* Has control virtqueue */
210235 bool has_cvq ;
211236
@@ -2184,6 +2209,57 @@ static void virtnet_get_ringparam(struct net_device *dev,
21842209 ring -> tx_pending = ring -> tx_max_pending ;
21852210}
21862211
2212+ static bool virtnet_commit_rss_command (struct virtnet_info * vi )
2213+ {
2214+ struct net_device * dev = vi -> dev ;
2215+ struct scatterlist sgs [4 ];
2216+ unsigned int sg_buf_size ;
2217+
2218+ /* prepare sgs */
2219+ sg_init_table (sgs , 4 );
2220+
2221+ sg_buf_size = offsetof(struct virtio_net_ctrl_rss , indirection_table );
2222+ sg_set_buf (& sgs [0 ], & vi -> ctrl -> rss , sg_buf_size );
2223+
2224+ sg_buf_size = sizeof (uint16_t ) * (vi -> ctrl -> rss .indirection_table_mask + 1 );
2225+ sg_set_buf (& sgs [1 ], vi -> ctrl -> rss .indirection_table , sg_buf_size );
2226+
2227+ sg_buf_size = offsetof(struct virtio_net_ctrl_rss , key )
2228+ - offsetof(struct virtio_net_ctrl_rss , max_tx_vq );
2229+ sg_set_buf (& sgs [2 ], & vi -> ctrl -> rss .max_tx_vq , sg_buf_size );
2230+
2231+ sg_buf_size = vi -> rss_key_size ;
2232+ sg_set_buf (& sgs [3 ], vi -> ctrl -> rss .key , sg_buf_size );
2233+
2234+ if (!virtnet_send_command (vi , VIRTIO_NET_CTRL_MQ ,
2235+ VIRTIO_NET_CTRL_MQ_RSS_CONFIG , sgs )) {
2236+ dev_warn (& dev -> dev , "VIRTIONET issue with committing RSS sgs\n" );
2237+ return false;
2238+ }
2239+ return true;
2240+ }
2241+
2242+ static void virtnet_init_default_rss (struct virtnet_info * vi )
2243+ {
2244+ u32 indir_val = 0 ;
2245+ int i = 0 ;
2246+
2247+ vi -> ctrl -> rss .hash_types = vi -> rss_hash_types_supported ;
2248+ vi -> ctrl -> rss .indirection_table_mask = vi -> rss_indir_table_size
2249+ ? vi -> rss_indir_table_size - 1 : 0 ;
2250+ vi -> ctrl -> rss .unclassified_queue = 0 ;
2251+
2252+ for (; i < vi -> rss_indir_table_size ; ++ i ) {
2253+ indir_val = ethtool_rxfh_indir_default (i , vi -> curr_queue_pairs );
2254+ vi -> ctrl -> rss .indirection_table [i ] = indir_val ;
2255+ }
2256+
2257+ vi -> ctrl -> rss .max_tx_vq = vi -> curr_queue_pairs ;
2258+ vi -> ctrl -> rss .hash_key_length = vi -> rss_key_size ;
2259+
2260+ netdev_rss_key_fill (vi -> ctrl -> rss .key , vi -> rss_key_size );
2261+ }
2262+
21872263
21882264static void virtnet_get_drvinfo (struct net_device * dev ,
21892265 struct ethtool_drvinfo * info )
@@ -2412,6 +2488,71 @@ static void virtnet_update_settings(struct virtnet_info *vi)
24122488 vi -> duplex = duplex ;
24132489}
24142490
2491+ static u32 virtnet_get_rxfh_key_size (struct net_device * dev )
2492+ {
2493+ return ((struct virtnet_info * )netdev_priv (dev ))-> rss_key_size ;
2494+ }
2495+
2496+ static u32 virtnet_get_rxfh_indir_size (struct net_device * dev )
2497+ {
2498+ return ((struct virtnet_info * )netdev_priv (dev ))-> rss_indir_table_size ;
2499+ }
2500+
2501+ static int virtnet_get_rxfh (struct net_device * dev , u32 * indir , u8 * key , u8 * hfunc )
2502+ {
2503+ struct virtnet_info * vi = netdev_priv (dev );
2504+ int i ;
2505+
2506+ if (indir ) {
2507+ for (i = 0 ; i < vi -> rss_indir_table_size ; ++ i )
2508+ indir [i ] = vi -> ctrl -> rss .indirection_table [i ];
2509+ }
2510+
2511+ if (key )
2512+ memcpy (key , vi -> ctrl -> rss .key , vi -> rss_key_size );
2513+
2514+ if (hfunc )
2515+ * hfunc = ETH_RSS_HASH_TOP ;
2516+
2517+ return 0 ;
2518+ }
2519+
2520+ static int virtnet_set_rxfh (struct net_device * dev , const u32 * indir , const u8 * key , const u8 hfunc )
2521+ {
2522+ struct virtnet_info * vi = netdev_priv (dev );
2523+ int i ;
2524+
2525+ if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP )
2526+ return - EOPNOTSUPP ;
2527+
2528+ if (indir ) {
2529+ for (i = 0 ; i < vi -> rss_indir_table_size ; ++ i )
2530+ vi -> ctrl -> rss .indirection_table [i ] = indir [i ];
2531+ }
2532+ if (key )
2533+ memcpy (vi -> ctrl -> rss .key , key , vi -> rss_key_size );
2534+
2535+ virtnet_commit_rss_command (vi );
2536+
2537+ return 0 ;
2538+ }
2539+
2540+ static int virtnet_get_rxnfc (struct net_device * dev , struct ethtool_rxnfc * info , u32 * rule_locs )
2541+ {
2542+ struct virtnet_info * vi = netdev_priv (dev );
2543+ int rc = 0 ;
2544+
2545+ switch (info -> cmd ) {
2546+ case ETHTOOL_GRXRINGS :
2547+ info -> data = vi -> curr_queue_pairs ;
2548+ break ;
2549+ default :
2550+ rc = - EOPNOTSUPP ;
2551+ }
2552+
2553+ return rc ;
2554+ }
2555+
24152556static const struct ethtool_ops virtnet_ethtool_ops = {
24162557 .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES ,
24172558 .get_drvinfo = virtnet_get_drvinfo ,
@@ -2427,6 +2568,11 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
24272568 .set_link_ksettings = virtnet_set_link_ksettings ,
24282569 .set_coalesce = virtnet_set_coalesce ,
24292570 .get_coalesce = virtnet_get_coalesce ,
2571+ .get_rxfh_key_size = virtnet_get_rxfh_key_size ,
2572+ .get_rxfh_indir_size = virtnet_get_rxfh_indir_size ,
2573+ .get_rxfh = virtnet_get_rxfh ,
2574+ .set_rxfh = virtnet_set_rxfh ,
2575+ .get_rxnfc = virtnet_get_rxnfc ,
24302576};
24312577
24322578static void virtnet_freeze_down (struct virtio_device * vdev )
@@ -2679,6 +2825,16 @@ static int virtnet_set_features(struct net_device *dev,
26792825 vi -> guest_offloads = offloads ;
26802826 }
26812827
2828+ if ((dev -> features ^ features ) & NETIF_F_RXHASH ) {
2829+ if (features & NETIF_F_RXHASH )
2830+ vi -> ctrl -> rss .hash_types = vi -> rss_hash_types_supported ;
2831+ else
2832+ vi -> ctrl -> rss .hash_types = VIRTIO_NET_HASH_REPORT_NONE ;
2833+
2834+ if (!virtnet_commit_rss_command (vi ))
2835+ return - EINVAL ;
2836+ }
2837+
26822838 return 0 ;
26832839}
26842840
@@ -3073,6 +3229,8 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
30733229 "VIRTIO_NET_F_CTRL_VQ" ) ||
30743230 VIRTNET_FAIL_ON (vdev , VIRTIO_NET_F_MQ , "VIRTIO_NET_F_CTRL_VQ" ) ||
30753231 VIRTNET_FAIL_ON (vdev , VIRTIO_NET_F_CTRL_MAC_ADDR ,
3232+ "VIRTIO_NET_F_CTRL_VQ" ) ||
3233+ VIRTNET_FAIL_ON (vdev , VIRTIO_NET_F_RSS ,
30763234 "VIRTIO_NET_F_CTRL_VQ" ))) {
30773235 return false;
30783236 }
@@ -3113,13 +3271,14 @@ static int virtnet_probe(struct virtio_device *vdev)
31133271 u16 max_queue_pairs ;
31143272 int mtu ;
31153273
3116- /* Find if host supports multiqueue virtio_net device */
3117- err = virtio_cread_feature (vdev , VIRTIO_NET_F_MQ ,
3118- struct virtio_net_config ,
3119- max_virtqueue_pairs , & max_queue_pairs );
3274+ /* Find if host supports multiqueue/rss virtio_net device */
3275+ max_queue_pairs = 1 ;
3276+ if (virtio_has_feature (vdev , VIRTIO_NET_F_MQ ) || virtio_has_feature (vdev , VIRTIO_NET_F_RSS ))
3277+ max_queue_pairs =
3278+ virtio_cread16 (vdev , offsetof(struct virtio_net_config , max_virtqueue_pairs ));
31203279
31213280 /* We need at least 2 queue's */
3122- if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
3281+ if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
31233282 max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
31243283 !virtio_has_feature (vdev , VIRTIO_NET_F_CTRL_VQ ))
31253284 max_queue_pairs = 1 ;
@@ -3207,6 +3366,23 @@ static int virtnet_probe(struct virtio_device *vdev)
32073366 if (virtio_has_feature (vdev , VIRTIO_NET_F_MRG_RXBUF ))
32083367 vi -> mergeable_rx_bufs = true;
32093368
3369+ if (virtio_has_feature (vdev , VIRTIO_NET_F_RSS )) {
3370+ vi -> has_rss = true;
3371+ vi -> rss_indir_table_size =
3372+ virtio_cread16 (vdev , offsetof(struct virtio_net_config ,
3373+ rss_max_indirection_table_length ));
3374+ vi -> rss_key_size =
3375+ virtio_cread8 (vdev , offsetof(struct virtio_net_config , rss_max_key_size ));
3376+
3377+ vi -> rss_hash_types_supported =
3378+ virtio_cread32 (vdev , offsetof(struct virtio_net_config , supported_hash_types ));
3379+ vi -> rss_hash_types_supported &=
3380+ ~(VIRTIO_NET_RSS_HASH_TYPE_IP_EX |
3381+ VIRTIO_NET_RSS_HASH_TYPE_TCP_EX |
3382+ VIRTIO_NET_RSS_HASH_TYPE_UDP_EX );
3383+
3384+ dev -> hw_features |= NETIF_F_RXHASH ;
3385+ }
32103386 if (virtio_has_feature (vdev , VIRTIO_NET_F_MRG_RXBUF ) ||
32113387 virtio_has_feature (vdev , VIRTIO_F_VERSION_1 ))
32123388 vi -> hdr_len = sizeof (struct virtio_net_hdr_mrg_rxbuf );
@@ -3275,6 +3451,9 @@ static int virtnet_probe(struct virtio_device *vdev)
32753451 }
32763452 }
32773453
3454+ if (vi -> has_rss )
3455+ virtnet_init_default_rss (vi );
3456+
32783457 err = register_netdev (dev );
32793458 if (err ) {
32803459 pr_debug ("virtio_net: registering device failed\n" );
@@ -3406,7 +3585,8 @@ static struct virtio_device_id id_table[] = {
34063585 VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
34073586 VIRTIO_NET_F_CTRL_MAC_ADDR, \
34083587 VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
3409- VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY
3588+ VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \
3589+ VIRTIO_NET_F_RSS
34103590
34113591static unsigned int features [] = {
34123592 VIRTNET_FEATURES ,
0 commit comments