@@ -312,6 +312,9 @@ struct receive_queue {
312
312
/* Is dynamic interrupt moderation enabled? */
313
313
bool dim_enabled ;
314
314
315
+ /* Used to protect dim_enabled and inter_coal */
316
+ struct mutex dim_lock ;
317
+
315
318
/* Dynamic Interrupt Moderation */
316
319
struct dim dim ;
317
320
@@ -2365,6 +2368,10 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
2365
2368
/* Out of packets? */
2366
2369
if (received < budget ) {
2367
2370
napi_complete = virtqueue_napi_complete (napi , rq -> vq , received );
2371
+ /* Intentionally not taking dim_lock here. This may result in a
2372
+ * spurious net_dim call. But if that happens virtnet_rx_dim_work
2373
+ * will not act on the scheduled work.
2374
+ */
2368
2375
if (napi_complete && rq -> dim_enabled )
2369
2376
virtnet_rx_dim_update (vi , rq );
2370
2377
}
@@ -3247,9 +3254,11 @@ static int virtnet_set_ringparam(struct net_device *dev,
3247
3254
return err ;
3248
3255
3249
3256
/* The reason is same as the transmit virtqueue reset */
3257
+ mutex_lock (& vi -> rq [i ].dim_lock );
3250
3258
err = virtnet_send_rx_ctrl_coal_vq_cmd (vi , i ,
3251
3259
vi -> intr_coal_rx .max_usecs ,
3252
3260
vi -> intr_coal_rx .max_packets );
3261
+ mutex_unlock (& vi -> rq [i ].dim_lock );
3253
3262
if (err )
3254
3263
return err ;
3255
3264
}
@@ -4255,6 +4264,7 @@ static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
4255
4264
struct virtio_net_ctrl_coal_rx * coal_rx __free (kfree ) = NULL ;
4256
4265
bool rx_ctrl_dim_on = !!ec -> use_adaptive_rx_coalesce ;
4257
4266
struct scatterlist sgs_rx ;
4267
+ int ret = 0 ;
4258
4268
int i ;
4259
4269
4260
4270
if (rx_ctrl_dim_on && !virtio_has_feature (vi -> vdev , VIRTIO_NET_F_VQ_NOTF_COAL ))
@@ -4264,16 +4274,22 @@ static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
4264
4274
ec -> rx_max_coalesced_frames != vi -> intr_coal_rx .max_packets ))
4265
4275
return - EINVAL ;
4266
4276
4277
+ /* Acquire all queues dim_locks */
4278
+ for (i = 0 ; i < vi -> max_queue_pairs ; i ++ )
4279
+ mutex_lock (& vi -> rq [i ].dim_lock );
4280
+
4267
4281
if (rx_ctrl_dim_on && !vi -> rx_dim_enabled ) {
4268
4282
vi -> rx_dim_enabled = true;
4269
4283
for (i = 0 ; i < vi -> max_queue_pairs ; i ++ )
4270
4284
vi -> rq [i ].dim_enabled = true;
4271
- return 0 ;
4285
+ goto unlock ;
4272
4286
}
4273
4287
4274
4288
coal_rx = kzalloc (sizeof (* coal_rx ), GFP_KERNEL );
4275
- if (!coal_rx )
4276
- return - ENOMEM ;
4289
+ if (!coal_rx ) {
4290
+ ret = - ENOMEM ;
4291
+ goto unlock ;
4292
+ }
4277
4293
4278
4294
if (!rx_ctrl_dim_on && vi -> rx_dim_enabled ) {
4279
4295
vi -> rx_dim_enabled = false;
@@ -4291,17 +4307,22 @@ static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
4291
4307
4292
4308
if (!virtnet_send_command (vi , VIRTIO_NET_CTRL_NOTF_COAL ,
4293
4309
VIRTIO_NET_CTRL_NOTF_COAL_RX_SET ,
4294
- & sgs_rx ))
4295
- return - EINVAL ;
4310
+ & sgs_rx )) {
4311
+ ret = - EINVAL ;
4312
+ goto unlock ;
4313
+ }
4296
4314
4297
4315
vi -> intr_coal_rx .max_usecs = ec -> rx_coalesce_usecs ;
4298
4316
vi -> intr_coal_rx .max_packets = ec -> rx_max_coalesced_frames ;
4299
4317
for (i = 0 ; i < vi -> max_queue_pairs ; i ++ ) {
4300
4318
vi -> rq [i ].intr_coal .max_usecs = ec -> rx_coalesce_usecs ;
4301
4319
vi -> rq [i ].intr_coal .max_packets = ec -> rx_max_coalesced_frames ;
4302
4320
}
4321
+ unlock :
4322
+ for (i = vi -> max_queue_pairs - 1 ; i >= 0 ; i -- )
4323
+ mutex_unlock (& vi -> rq [i ].dim_lock );
4303
4324
4304
- return 0 ;
4325
+ return ret ;
4305
4326
}
4306
4327
4307
4328
static int virtnet_send_notf_coal_cmds (struct virtnet_info * vi ,
@@ -4325,19 +4346,24 @@ static int virtnet_send_rx_notf_coal_vq_cmds(struct virtnet_info *vi,
4325
4346
u16 queue )
4326
4347
{
4327
4348
bool rx_ctrl_dim_on = !!ec -> use_adaptive_rx_coalesce ;
4328
- bool cur_rx_dim = vi -> rq [queue ].dim_enabled ;
4329
4349
u32 max_usecs , max_packets ;
4350
+ bool cur_rx_dim ;
4330
4351
int err ;
4331
4352
4353
+ mutex_lock (& vi -> rq [queue ].dim_lock );
4354
+ cur_rx_dim = vi -> rq [queue ].dim_enabled ;
4332
4355
max_usecs = vi -> rq [queue ].intr_coal .max_usecs ;
4333
4356
max_packets = vi -> rq [queue ].intr_coal .max_packets ;
4334
4357
4335
4358
if (rx_ctrl_dim_on && (ec -> rx_coalesce_usecs != max_usecs ||
4336
- ec -> rx_max_coalesced_frames != max_packets ))
4359
+ ec -> rx_max_coalesced_frames != max_packets )) {
4360
+ mutex_unlock (& vi -> rq [queue ].dim_lock );
4337
4361
return - EINVAL ;
4362
+ }
4338
4363
4339
4364
if (rx_ctrl_dim_on && !cur_rx_dim ) {
4340
4365
vi -> rq [queue ].dim_enabled = true;
4366
+ mutex_unlock (& vi -> rq [queue ].dim_lock );
4341
4367
return 0 ;
4342
4368
}
4343
4369
@@ -4350,10 +4376,8 @@ static int virtnet_send_rx_notf_coal_vq_cmds(struct virtnet_info *vi,
4350
4376
err = virtnet_send_rx_ctrl_coal_vq_cmd (vi , queue ,
4351
4377
ec -> rx_coalesce_usecs ,
4352
4378
ec -> rx_max_coalesced_frames );
4353
- if (err )
4354
- return err ;
4355
-
4356
- return 0 ;
4379
+ mutex_unlock (& vi -> rq [queue ].dim_lock );
4380
+ return err ;
4357
4381
}
4358
4382
4359
4383
static int virtnet_send_notf_coal_vq_cmds (struct virtnet_info * vi ,
@@ -4390,6 +4414,7 @@ static void virtnet_rx_dim_work(struct work_struct *work)
4390
4414
4391
4415
qnum = rq - vi -> rq ;
4392
4416
4417
+ mutex_lock (& rq -> dim_lock );
4393
4418
if (!rq -> dim_enabled )
4394
4419
goto out ;
4395
4420
@@ -4405,6 +4430,7 @@ static void virtnet_rx_dim_work(struct work_struct *work)
4405
4430
dim -> state = DIM_START_MEASURE ;
4406
4431
}
4407
4432
out :
4433
+ mutex_unlock (& rq -> dim_lock );
4408
4434
rtnl_unlock ();
4409
4435
}
4410
4436
@@ -4543,11 +4569,13 @@ static int virtnet_get_per_queue_coalesce(struct net_device *dev,
4543
4569
return - EINVAL ;
4544
4570
4545
4571
if (virtio_has_feature (vi -> vdev , VIRTIO_NET_F_VQ_NOTF_COAL )) {
4572
+ mutex_lock (& vi -> rq [queue ].dim_lock );
4546
4573
ec -> rx_coalesce_usecs = vi -> rq [queue ].intr_coal .max_usecs ;
4547
4574
ec -> tx_coalesce_usecs = vi -> sq [queue ].intr_coal .max_usecs ;
4548
4575
ec -> tx_max_coalesced_frames = vi -> sq [queue ].intr_coal .max_packets ;
4549
4576
ec -> rx_max_coalesced_frames = vi -> rq [queue ].intr_coal .max_packets ;
4550
4577
ec -> use_adaptive_rx_coalesce = vi -> rq [queue ].dim_enabled ;
4578
+ mutex_unlock (& vi -> rq [queue ].dim_lock );
4551
4579
} else {
4552
4580
ec -> rx_max_coalesced_frames = 1 ;
4553
4581
@@ -5377,6 +5405,7 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
5377
5405
5378
5406
u64_stats_init (& vi -> rq [i ].stats .syncp );
5379
5407
u64_stats_init (& vi -> sq [i ].stats .syncp );
5408
+ mutex_init (& vi -> rq [i ].dim_lock );
5380
5409
}
5381
5410
5382
5411
return 0 ;
0 commit comments