@@ -368,15 +368,16 @@ struct receive_queue {
368
368
* because table sizes may be differ according to the device configuration.
369
369
*/
370
370
#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
371
- #define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
372
371
struct virtio_net_ctrl_rss {
373
372
u32 hash_types ;
374
373
u16 indirection_table_mask ;
375
374
u16 unclassified_queue ;
376
- u16 indirection_table [ VIRTIO_NET_RSS_MAX_TABLE_LEN ];
375
+ u16 hash_cfg_reserved ; /* for HASH_CONFIG (see virtio_net_hash_config for details) */
377
376
u16 max_tx_vq ;
378
377
u8 hash_key_length ;
379
378
u8 key [VIRTIO_NET_RSS_MAX_KEY_SIZE ];
379
+
380
+ u16 * indirection_table ;
380
381
};
381
382
382
383
/* Control VQ buffers: protected by the rtnl lock */
@@ -512,6 +513,25 @@ static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb,
512
513
struct page * page , void * buf ,
513
514
int len , int truesize );
514
515
516
+ static int rss_indirection_table_alloc (struct virtio_net_ctrl_rss * rss , u16 indir_table_size )
517
+ {
518
+ if (!indir_table_size ) {
519
+ rss -> indirection_table = NULL ;
520
+ return 0 ;
521
+ }
522
+
523
+ rss -> indirection_table = kmalloc_array (indir_table_size , sizeof (u16 ), GFP_KERNEL );
524
+ if (!rss -> indirection_table )
525
+ return - ENOMEM ;
526
+
527
+ return 0 ;
528
+ }
529
+
530
+ static void rss_indirection_table_free (struct virtio_net_ctrl_rss * rss )
531
+ {
532
+ kfree (rss -> indirection_table );
533
+ }
534
+
515
535
static bool is_xdp_frame (void * ptr )
516
536
{
517
537
return (unsigned long )ptr & VIRTIO_XDP_FLAG ;
@@ -3374,15 +3394,59 @@ static void virtnet_ack_link_announce(struct virtnet_info *vi)
3374
3394
dev_warn (& vi -> dev -> dev , "Failed to ack link announce.\n" );
3375
3395
}
3376
3396
3397
+ static bool virtnet_commit_rss_command (struct virtnet_info * vi );
3398
+
3399
+ static void virtnet_rss_update_by_qpairs (struct virtnet_info * vi , u16 queue_pairs )
3400
+ {
3401
+ u32 indir_val = 0 ;
3402
+ int i = 0 ;
3403
+
3404
+ for (; i < vi -> rss_indir_table_size ; ++ i ) {
3405
+ indir_val = ethtool_rxfh_indir_default (i , queue_pairs );
3406
+ vi -> rss .indirection_table [i ] = indir_val ;
3407
+ }
3408
+ vi -> rss .max_tx_vq = queue_pairs ;
3409
+ }
3410
+
3377
3411
static int virtnet_set_queues (struct virtnet_info * vi , u16 queue_pairs )
3378
3412
{
3379
3413
struct virtio_net_ctrl_mq * mq __free (kfree ) = NULL ;
3380
- struct scatterlist sg ;
3414
+ struct virtio_net_ctrl_rss old_rss ;
3381
3415
struct net_device * dev = vi -> dev ;
3416
+ struct scatterlist sg ;
3382
3417
3383
3418
if (!vi -> has_cvq || !virtio_has_feature (vi -> vdev , VIRTIO_NET_F_MQ ))
3384
3419
return 0 ;
3385
3420
3421
+ /* Firstly check if we need update rss. Do updating if both (1) rss enabled and
3422
+ * (2) no user configuration.
3423
+ *
3424
+ * During rss command processing, device updates queue_pairs using rss.max_tx_vq. That is,
3425
+ * the device updates queue_pairs together with rss, so we can skip the sperate queue_pairs
3426
+ * update (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET below) and return directly.
3427
+ */
3428
+ if (vi -> has_rss && !netif_is_rxfh_configured (dev )) {
3429
+ memcpy (& old_rss , & vi -> rss , sizeof (old_rss ));
3430
+ if (rss_indirection_table_alloc (& vi -> rss , vi -> rss_indir_table_size )) {
3431
+ vi -> rss .indirection_table = old_rss .indirection_table ;
3432
+ return - ENOMEM ;
3433
+ }
3434
+
3435
+ virtnet_rss_update_by_qpairs (vi , queue_pairs );
3436
+
3437
+ if (!virtnet_commit_rss_command (vi )) {
3438
+ /* restore ctrl_rss if commit_rss_command failed */
3439
+ rss_indirection_table_free (& vi -> rss );
3440
+ memcpy (& vi -> rss , & old_rss , sizeof (old_rss ));
3441
+
3442
+ dev_warn (& dev -> dev , "Fail to set num of queue pairs to %d, because committing RSS failed\n" ,
3443
+ queue_pairs );
3444
+ return - EINVAL ;
3445
+ }
3446
+ rss_indirection_table_free (& old_rss );
3447
+ goto succ ;
3448
+ }
3449
+
3386
3450
mq = kzalloc (sizeof (* mq ), GFP_KERNEL );
3387
3451
if (!mq )
3388
3452
return - ENOMEM ;
@@ -3395,12 +3459,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
3395
3459
dev_warn (& dev -> dev , "Fail to set num of queue pairs to %d\n" ,
3396
3460
queue_pairs );
3397
3461
return - EINVAL ;
3398
- } else {
3399
- vi -> curr_queue_pairs = queue_pairs ;
3400
- /* virtnet_open() will refill when device is going to up. */
3401
- if (dev -> flags & IFF_UP )
3402
- schedule_delayed_work (& vi -> refill , 0 );
3403
3462
}
3463
+ succ :
3464
+ vi -> curr_queue_pairs = queue_pairs ;
3465
+ /* virtnet_open() will refill when device is going to up. */
3466
+ if (dev -> flags & IFF_UP )
3467
+ schedule_delayed_work (& vi -> refill , 0 );
3404
3468
3405
3469
return 0 ;
3406
3470
}
@@ -3828,11 +3892,15 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
3828
3892
/* prepare sgs */
3829
3893
sg_init_table (sgs , 4 );
3830
3894
3831
- sg_buf_size = offsetof(struct virtio_net_ctrl_rss , indirection_table );
3895
+ sg_buf_size = offsetof(struct virtio_net_ctrl_rss , hash_cfg_reserved );
3832
3896
sg_set_buf (& sgs [0 ], & vi -> rss , sg_buf_size );
3833
3897
3834
- sg_buf_size = sizeof (uint16_t ) * (vi -> rss .indirection_table_mask + 1 );
3835
- sg_set_buf (& sgs [1 ], vi -> rss .indirection_table , sg_buf_size );
3898
+ if (vi -> has_rss ) {
3899
+ sg_buf_size = sizeof (uint16_t ) * vi -> rss_indir_table_size ;
3900
+ sg_set_buf (& sgs [1 ], vi -> rss .indirection_table , sg_buf_size );
3901
+ } else {
3902
+ sg_set_buf (& sgs [1 ], & vi -> rss .hash_cfg_reserved , sizeof (uint16_t ));
3903
+ }
3836
3904
3837
3905
sg_buf_size = offsetof(struct virtio_net_ctrl_rss , key )
3838
3906
- offsetof(struct virtio_net_ctrl_rss , max_tx_vq );
@@ -3856,21 +3924,14 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
3856
3924
3857
3925
static void virtnet_init_default_rss (struct virtnet_info * vi )
3858
3926
{
3859
- u32 indir_val = 0 ;
3860
- int i = 0 ;
3861
-
3862
3927
vi -> rss .hash_types = vi -> rss_hash_types_supported ;
3863
3928
vi -> rss_hash_types_saved = vi -> rss_hash_types_supported ;
3864
3929
vi -> rss .indirection_table_mask = vi -> rss_indir_table_size
3865
3930
? vi -> rss_indir_table_size - 1 : 0 ;
3866
3931
vi -> rss .unclassified_queue = 0 ;
3867
3932
3868
- for (; i < vi -> rss_indir_table_size ; ++ i ) {
3869
- indir_val = ethtool_rxfh_indir_default (i , vi -> curr_queue_pairs );
3870
- vi -> rss .indirection_table [i ] = indir_val ;
3871
- }
3933
+ virtnet_rss_update_by_qpairs (vi , vi -> curr_queue_pairs );
3872
3934
3873
- vi -> rss .max_tx_vq = vi -> has_rss ? vi -> curr_queue_pairs : 0 ;
3874
3935
vi -> rss .hash_key_length = vi -> rss_key_size ;
3875
3936
3876
3937
netdev_rss_key_fill (vi -> rss .key , vi -> rss_key_size );
@@ -6420,10 +6481,19 @@ static int virtnet_probe(struct virtio_device *vdev)
6420
6481
virtio_cread16 (vdev , offsetof(struct virtio_net_config ,
6421
6482
rss_max_indirection_table_length ));
6422
6483
}
6484
+ err = rss_indirection_table_alloc (& vi -> rss , vi -> rss_indir_table_size );
6485
+ if (err )
6486
+ goto free ;
6423
6487
6424
6488
if (vi -> has_rss || vi -> has_rss_hash_report ) {
6425
6489
vi -> rss_key_size =
6426
6490
virtio_cread8 (vdev , offsetof(struct virtio_net_config , rss_max_key_size ));
6491
+ if (vi -> rss_key_size > VIRTIO_NET_RSS_MAX_KEY_SIZE ) {
6492
+ dev_err (& vdev -> dev , "rss_max_key_size=%u exceeds the limit %u.\n" ,
6493
+ vi -> rss_key_size , VIRTIO_NET_RSS_MAX_KEY_SIZE );
6494
+ err = - EINVAL ;
6495
+ goto free ;
6496
+ }
6427
6497
6428
6498
vi -> rss_hash_types_supported =
6429
6499
virtio_cread32 (vdev , offsetof(struct virtio_net_config , supported_hash_types ));
@@ -6551,6 +6621,15 @@ static int virtnet_probe(struct virtio_device *vdev)
6551
6621
6552
6622
virtio_device_ready (vdev );
6553
6623
6624
+ if (vi -> has_rss || vi -> has_rss_hash_report ) {
6625
+ if (!virtnet_commit_rss_command (vi )) {
6626
+ dev_warn (& vdev -> dev , "RSS disabled because committing failed.\n" );
6627
+ dev -> hw_features &= ~NETIF_F_RXHASH ;
6628
+ vi -> has_rss_hash_report = false;
6629
+ vi -> has_rss = false;
6630
+ }
6631
+ }
6632
+
6554
6633
virtnet_set_queues (vi , vi -> curr_queue_pairs );
6555
6634
6556
6635
/* a random MAC address has been assigned, notify the device.
@@ -6674,6 +6753,8 @@ static void virtnet_remove(struct virtio_device *vdev)
6674
6753
6675
6754
remove_vq_common (vi );
6676
6755
6756
+ rss_indirection_table_free (& vi -> rss );
6757
+
6677
6758
free_netdev (vi -> dev );
6678
6759
}
6679
6760
0 commit comments