Skip to content

Commit 394bd87

Browse files
GavinLi-NVkuba-moo
authored andcommitted
virtio_net: support per queue interrupt coalesce command
Add interrupt_coalesce config in send_queue and receive_queue to cache user config. Send per virtqueue interrupt moderation config to underlying device in order to have more efficient interrupt moderation and cpu utilization of guest VM. Additionally, address all the VQs when updating the global configuration, as now the individual VQs configuration can diverge from the global configuration. Signed-off-by: Gavin Li <gavinl@nvidia.com> Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Reviewed-by: Heng Qi <hengqi@linux.alibaba.com> Acked-by: Jason Wang <jasowang@redhat.com> Link: https://lore.kernel.org/r/20230731070656.96411-3-gavinl@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 308d798 commit 394bd87

File tree

2 files changed

+155
-8
lines changed

2 files changed

+155
-8
lines changed

drivers/net/virtio_net.c

Lines changed: 141 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ struct send_queue {
144144

145145
struct virtnet_sq_stats stats;
146146

147+
struct virtnet_interrupt_coalesce intr_coal;
148+
147149
struct napi_struct napi;
148150

149151
/* Record whether sq is in reset state. */
@@ -161,6 +163,8 @@ struct receive_queue {
161163

162164
struct virtnet_rq_stats stats;
163165

166+
struct virtnet_interrupt_coalesce intr_coal;
167+
164168
/* Chain pages by the private ptr. */
165169
struct page *pages;
166170

@@ -212,6 +216,7 @@ struct control_buf {
212216
struct virtio_net_ctrl_rss rss;
213217
struct virtio_net_ctrl_coal_tx coal_tx;
214218
struct virtio_net_ctrl_coal_rx coal_rx;
219+
struct virtio_net_ctrl_coal_vq coal_vq;
215220
};
216221

217222
struct virtnet_info {
@@ -3078,6 +3083,55 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
30783083
return 0;
30793084
}
30803085

3086+
static int virtnet_send_ctrl_coal_vq_cmd(struct virtnet_info *vi,
3087+
u16 vqn, u32 max_usecs, u32 max_packets)
3088+
{
3089+
struct scatterlist sgs;
3090+
3091+
vi->ctrl->coal_vq.vqn = cpu_to_le16(vqn);
3092+
vi->ctrl->coal_vq.coal.max_usecs = cpu_to_le32(max_usecs);
3093+
vi->ctrl->coal_vq.coal.max_packets = cpu_to_le32(max_packets);
3094+
sg_init_one(&sgs, &vi->ctrl->coal_vq, sizeof(vi->ctrl->coal_vq));
3095+
3096+
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
3097+
VIRTIO_NET_CTRL_NOTF_COAL_VQ_SET,
3098+
&sgs))
3099+
return -EINVAL;
3100+
3101+
return 0;
3102+
}
3103+
3104+
static int virtnet_send_notf_coal_vq_cmds(struct virtnet_info *vi,
3105+
struct ethtool_coalesce *ec,
3106+
u16 queue)
3107+
{
3108+
int err;
3109+
3110+
if (ec->rx_coalesce_usecs || ec->rx_max_coalesced_frames) {
3111+
err = virtnet_send_ctrl_coal_vq_cmd(vi, rxq2vq(queue),
3112+
ec->rx_coalesce_usecs,
3113+
ec->rx_max_coalesced_frames);
3114+
if (err)
3115+
return err;
3116+
/* Save parameters */
3117+
vi->rq[queue].intr_coal.max_usecs = ec->rx_coalesce_usecs;
3118+
vi->rq[queue].intr_coal.max_packets = ec->rx_max_coalesced_frames;
3119+
}
3120+
3121+
if (ec->tx_coalesce_usecs || ec->tx_max_coalesced_frames) {
3122+
err = virtnet_send_ctrl_coal_vq_cmd(vi, txq2vq(queue),
3123+
ec->tx_coalesce_usecs,
3124+
ec->tx_max_coalesced_frames);
3125+
if (err)
3126+
return err;
3127+
/* Save parameters */
3128+
vi->sq[queue].intr_coal.max_usecs = ec->tx_coalesce_usecs;
3129+
vi->sq[queue].intr_coal.max_packets = ec->tx_max_coalesced_frames;
3130+
}
3131+
3132+
return 0;
3133+
}
3134+
30813135
static int virtnet_coal_params_supported(struct ethtool_coalesce *ec)
30823136
{
30833137
/* usecs coalescing is supported only if VIRTIO_NET_F_NOTF_COAL
@@ -3093,22 +3147,42 @@ static int virtnet_coal_params_supported(struct ethtool_coalesce *ec)
30933147
return 0;
30943148
}
30953149

3150+
static int virtnet_should_update_vq_weight(int dev_flags, int weight,
3151+
int vq_weight, bool *should_update)
3152+
{
3153+
if (weight ^ vq_weight) {
3154+
if (dev_flags & IFF_UP)
3155+
return -EBUSY;
3156+
*should_update = true;
3157+
}
3158+
3159+
return 0;
3160+
}
3161+
30963162
static int virtnet_set_coalesce(struct net_device *dev,
30973163
struct ethtool_coalesce *ec,
30983164
struct kernel_ethtool_coalesce *kernel_coal,
30993165
struct netlink_ext_ack *extack)
31003166
{
31013167
struct virtnet_info *vi = netdev_priv(dev);
3102-
int ret, i, napi_weight;
3168+
int ret, queue_number, napi_weight;
31033169
bool update_napi = false;
31043170

31053171
/* Can't change NAPI weight if the link is up */
31063172
napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
3107-
if (napi_weight ^ vi->sq[0].napi.weight) {
3108-
if (dev->flags & IFF_UP)
3109-
return -EBUSY;
3110-
else
3111-
update_napi = true;
3173+
for (queue_number = 0; queue_number < vi->max_queue_pairs; queue_number++) {
3174+
ret = virtnet_should_update_vq_weight(dev->flags, napi_weight,
3175+
vi->sq[queue_number].napi.weight,
3176+
&update_napi);
3177+
if (ret)
3178+
return ret;
3179+
3180+
if (update_napi) {
3181+
/* All queues that belong to [queue_number, vi->max_queue_pairs] will be
3182+
* updated for the sake of simplicity, which might not be necessary
3183+
*/
3184+
break;
3185+
}
31123186
}
31133187

31143188
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL))
@@ -3120,8 +3194,8 @@ static int virtnet_set_coalesce(struct net_device *dev,
31203194
return ret;
31213195

31223196
if (update_napi) {
3123-
for (i = 0; i < vi->max_queue_pairs; i++)
3124-
vi->sq[i].napi.weight = napi_weight;
3197+
for (; queue_number < vi->max_queue_pairs; queue_number++)
3198+
vi->sq[queue_number].napi.weight = napi_weight;
31253199
}
31263200

31273201
return ret;
@@ -3149,6 +3223,63 @@ static int virtnet_get_coalesce(struct net_device *dev,
31493223
return 0;
31503224
}
31513225

3226+
static int virtnet_set_per_queue_coalesce(struct net_device *dev,
3227+
u32 queue,
3228+
struct ethtool_coalesce *ec)
3229+
{
3230+
struct virtnet_info *vi = netdev_priv(dev);
3231+
int ret, napi_weight;
3232+
bool update_napi = false;
3233+
3234+
if (queue >= vi->max_queue_pairs)
3235+
return -EINVAL;
3236+
3237+
/* Can't change NAPI weight if the link is up */
3238+
napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
3239+
ret = virtnet_should_update_vq_weight(dev->flags, napi_weight,
3240+
vi->sq[queue].napi.weight,
3241+
&update_napi);
3242+
if (ret)
3243+
return ret;
3244+
3245+
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
3246+
ret = virtnet_send_notf_coal_vq_cmds(vi, ec, queue);
3247+
else
3248+
ret = virtnet_coal_params_supported(ec);
3249+
3250+
if (ret)
3251+
return ret;
3252+
3253+
if (update_napi)
3254+
vi->sq[queue].napi.weight = napi_weight;
3255+
3256+
return 0;
3257+
}
3258+
3259+
static int virtnet_get_per_queue_coalesce(struct net_device *dev,
3260+
u32 queue,
3261+
struct ethtool_coalesce *ec)
3262+
{
3263+
struct virtnet_info *vi = netdev_priv(dev);
3264+
3265+
if (queue >= vi->max_queue_pairs)
3266+
return -EINVAL;
3267+
3268+
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL)) {
3269+
ec->rx_coalesce_usecs = vi->rq[queue].intr_coal.max_usecs;
3270+
ec->tx_coalesce_usecs = vi->sq[queue].intr_coal.max_usecs;
3271+
ec->tx_max_coalesced_frames = vi->sq[queue].intr_coal.max_packets;
3272+
ec->rx_max_coalesced_frames = vi->rq[queue].intr_coal.max_packets;
3273+
} else {
3274+
ec->rx_max_coalesced_frames = 1;
3275+
3276+
if (vi->sq[0].napi.weight)
3277+
ec->tx_max_coalesced_frames = 1;
3278+
}
3279+
3280+
return 0;
3281+
}
3282+
31523283
static void virtnet_init_settings(struct net_device *dev)
31533284
{
31543285
struct virtnet_info *vi = netdev_priv(dev);
@@ -3279,6 +3410,8 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
32793410
.set_link_ksettings = virtnet_set_link_ksettings,
32803411
.set_coalesce = virtnet_set_coalesce,
32813412
.get_coalesce = virtnet_get_coalesce,
3413+
.set_per_queue_coalesce = virtnet_set_per_queue_coalesce,
3414+
.get_per_queue_coalesce = virtnet_get_per_queue_coalesce,
32823415
.get_rxfh_key_size = virtnet_get_rxfh_key_size,
32833416
.get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
32843417
.get_rxfh = virtnet_get_rxfh,

include/uapi/linux/virtio_net.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow
5757
* Steering */
5858
#define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */
59+
#define VIRTIO_NET_F_VQ_NOTF_COAL 52 /* Device supports virtqueue notification coalescing */
5960
#define VIRTIO_NET_F_NOTF_COAL 53 /* Device supports notifications coalescing */
6061
#define VIRTIO_NET_F_GUEST_USO4 54 /* Guest can handle USOv4 in. */
6162
#define VIRTIO_NET_F_GUEST_USO6 55 /* Guest can handle USOv6 in. */
@@ -391,5 +392,18 @@ struct virtio_net_ctrl_coal_rx {
391392
};
392393

393394
#define VIRTIO_NET_CTRL_NOTF_COAL_RX_SET 1
395+
#define VIRTIO_NET_CTRL_NOTF_COAL_VQ_SET 2
396+
#define VIRTIO_NET_CTRL_NOTF_COAL_VQ_GET 3
397+
398+
struct virtio_net_ctrl_coal {
399+
__le32 max_packets;
400+
__le32 max_usecs;
401+
};
402+
403+
struct virtio_net_ctrl_coal_vq {
404+
__le16 vqn;
405+
__le16 reserved;
406+
struct virtio_net_ctrl_coal coal;
407+
};
394408

395409
#endif /* _UAPI_LINUX_VIRTIO_NET_H */

0 commit comments

Comments
 (0)