Skip to content

Commit b9e643f

Browse files
committed
Merge branch 'virtio_net-add-per-queue-interrupt-coalescing-support'
Gavin Li says: ==================== virtio_net: add per queue interrupt coalescing support Currently, coalescing parameters are grouped for all transmit and receive virtqueues. This patch series add support to set or get the parameters for a specified virtqueue. When the traffic between virtqueues is unbalanced, for example, one virtqueue is busy and another virtqueue is idle, then it will be very useful to control coalescing parameters at the virtqueue granularity. Example command: $ ethtool -Q eth5 queue_mask 0x1 --coalesce tx-packets 10 Would set max_packets=10 to VQ 1. $ ethtool -Q eth5 queue_mask 0x1 --coalesce rx-packets 10 Would set max_packets=10 to VQ 0. $ ethtool -Q eth5 queue_mask 0x1 --show-coalesce Queue: 0 Adaptive RX: off TX: off stats-block-usecs: 0 sample-interval: 0 pkt-rate-low: 0 pkt-rate-high: 0 rx-usecs: 222 rx-frames: 0 rx-usecs-irq: 0 rx-frames-irq: 256 tx-usecs: 222 tx-frames: 0 tx-usecs-irq: 0 tx-frames-irq: 256 rx-usecs-low: 0 rx-frame-low: 0 tx-usecs-low: 0 tx-frame-low: 0 rx-usecs-high: 0 rx-frame-high: 0 tx-usecs-high: 0 tx-frame-high: 0 ==================== Link: https://lore.kernel.org/r/20230731070656.96411-1-gavinl@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 999d086 + 8af3bf6 commit b9e643f

File tree

2 files changed

+177
-24
lines changed

2 files changed

+177
-24
lines changed

drivers/net/virtio_net.c

Lines changed: 163 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = {
126126
#define VIRTNET_SQ_STATS_LEN ARRAY_SIZE(virtnet_sq_stats_desc)
127127
#define VIRTNET_RQ_STATS_LEN ARRAY_SIZE(virtnet_rq_stats_desc)
128128

129+
struct virtnet_interrupt_coalesce {
130+
u32 max_packets;
131+
u32 max_usecs;
132+
};
133+
129134
/* Internal representation of a send virtqueue */
130135
struct send_queue {
131136
/* Virtqueue associated with this send _queue */
@@ -139,6 +144,8 @@ struct send_queue {
139144

140145
struct virtnet_sq_stats stats;
141146

147+
struct virtnet_interrupt_coalesce intr_coal;
148+
142149
struct napi_struct napi;
143150

144151
/* Record whether sq is in reset state. */
@@ -156,6 +163,8 @@ struct receive_queue {
156163

157164
struct virtnet_rq_stats stats;
158165

166+
struct virtnet_interrupt_coalesce intr_coal;
167+
159168
/* Chain pages by the private ptr. */
160169
struct page *pages;
161170

@@ -207,6 +216,7 @@ struct control_buf {
207216
struct virtio_net_ctrl_rss rss;
208217
struct virtio_net_ctrl_coal_tx coal_tx;
209218
struct virtio_net_ctrl_coal_rx coal_rx;
219+
struct virtio_net_ctrl_coal_vq coal_vq;
210220
};
211221

212222
struct virtnet_info {
@@ -281,10 +291,8 @@ struct virtnet_info {
281291
u32 speed;
282292

283293
/* Interrupt coalescing settings */
284-
u32 tx_usecs;
285-
u32 rx_usecs;
286-
u32 tx_max_packets;
287-
u32 rx_max_packets;
294+
struct virtnet_interrupt_coalesce intr_coal_tx;
295+
struct virtnet_interrupt_coalesce intr_coal_rx;
288296

289297
unsigned long guest_offloads;
290298
unsigned long guest_offloads_capable;
@@ -3056,8 +3064,8 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
30563064
return -EINVAL;
30573065

30583066
/* Save parameters */
3059-
vi->tx_usecs = ec->tx_coalesce_usecs;
3060-
vi->tx_max_packets = ec->tx_max_coalesced_frames;
3067+
vi->intr_coal_tx.max_usecs = ec->tx_coalesce_usecs;
3068+
vi->intr_coal_tx.max_packets = ec->tx_max_coalesced_frames;
30613069

30623070
vi->ctrl->coal_rx.rx_usecs = cpu_to_le32(ec->rx_coalesce_usecs);
30633071
vi->ctrl->coal_rx.rx_max_packets = cpu_to_le32(ec->rx_max_coalesced_frames);
@@ -3069,8 +3077,57 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
30693077
return -EINVAL;
30703078

30713079
/* Save parameters */
3072-
vi->rx_usecs = ec->rx_coalesce_usecs;
3073-
vi->rx_max_packets = ec->rx_max_coalesced_frames;
3080+
vi->intr_coal_rx.max_usecs = ec->rx_coalesce_usecs;
3081+
vi->intr_coal_rx.max_packets = ec->rx_max_coalesced_frames;
3082+
3083+
return 0;
3084+
}
3085+
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+
}
30743131

30753132
return 0;
30763133
}
@@ -3090,22 +3147,42 @@ static int virtnet_coal_params_supported(struct ethtool_coalesce *ec)
30903147
return 0;
30913148
}
30923149

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+
30933162
static int virtnet_set_coalesce(struct net_device *dev,
30943163
struct ethtool_coalesce *ec,
30953164
struct kernel_ethtool_coalesce *kernel_coal,
30963165
struct netlink_ext_ack *extack)
30973166
{
30983167
struct virtnet_info *vi = netdev_priv(dev);
3099-
int ret, i, napi_weight;
3168+
int ret, queue_number, napi_weight;
31003169
bool update_napi = false;
31013170

31023171
/* Can't change NAPI weight if the link is up */
31033172
napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
3104-
if (napi_weight ^ vi->sq[0].napi.weight) {
3105-
if (dev->flags & IFF_UP)
3106-
return -EBUSY;
3107-
else
3108-
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+
}
31093186
}
31103187

31113188
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL))
@@ -3117,8 +3194,8 @@ static int virtnet_set_coalesce(struct net_device *dev,
31173194
return ret;
31183195

31193196
if (update_napi) {
3120-
for (i = 0; i < vi->max_queue_pairs; i++)
3121-
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;
31223199
}
31233200

31243201
return ret;
@@ -3132,10 +3209,67 @@ static int virtnet_get_coalesce(struct net_device *dev,
31323209
struct virtnet_info *vi = netdev_priv(dev);
31333210

31343211
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
3135-
ec->rx_coalesce_usecs = vi->rx_usecs;
3136-
ec->tx_coalesce_usecs = vi->tx_usecs;
3137-
ec->tx_max_coalesced_frames = vi->tx_max_packets;
3138-
ec->rx_max_coalesced_frames = vi->rx_max_packets;
3212+
ec->rx_coalesce_usecs = vi->intr_coal_rx.max_usecs;
3213+
ec->tx_coalesce_usecs = vi->intr_coal_tx.max_usecs;
3214+
ec->tx_max_coalesced_frames = vi->intr_coal_tx.max_packets;
3215+
ec->rx_max_coalesced_frames = vi->intr_coal_rx.max_packets;
3216+
} else {
3217+
ec->rx_max_coalesced_frames = 1;
3218+
3219+
if (vi->sq[0].napi.weight)
3220+
ec->tx_max_coalesced_frames = 1;
3221+
}
3222+
3223+
return 0;
3224+
}
3225+
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;
31393273
} else {
31403274
ec->rx_max_coalesced_frames = 1;
31413275

@@ -3276,6 +3410,8 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
32763410
.set_link_ksettings = virtnet_set_link_ksettings,
32773411
.set_coalesce = virtnet_set_coalesce,
32783412
.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,
32793415
.get_rxfh_key_size = virtnet_get_rxfh_key_size,
32803416
.get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
32813417
.get_rxfh = virtnet_get_rxfh,
@@ -3952,6 +4088,8 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
39524088
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
39534089
"VIRTIO_NET_F_CTRL_VQ") ||
39544090
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_NOTF_COAL,
4091+
"VIRTIO_NET_F_CTRL_VQ") ||
4092+
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_VQ_NOTF_COAL,
39554093
"VIRTIO_NET_F_CTRL_VQ"))) {
39564094
return false;
39574095
}
@@ -4119,10 +4257,10 @@ static int virtnet_probe(struct virtio_device *vdev)
41194257
}
41204258

41214259
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
4122-
vi->rx_usecs = 0;
4123-
vi->tx_usecs = 0;
4124-
vi->tx_max_packets = 0;
4125-
vi->rx_max_packets = 0;
4260+
vi->intr_coal_rx.max_usecs = 0;
4261+
vi->intr_coal_tx.max_usecs = 0;
4262+
vi->intr_coal_tx.max_packets = 0;
4263+
vi->intr_coal_rx.max_packets = 0;
41264264
}
41274265

41284266
if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT))
@@ -4376,6 +4514,7 @@ static struct virtio_device_id id_table[] = {
43764514
VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
43774515
VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \
43784516
VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT, VIRTIO_NET_F_NOTF_COAL, \
4517+
VIRTIO_NET_F_VQ_NOTF_COAL, \
43794518
VIRTIO_NET_F_GUEST_HDRLEN
43804519

43814520
static unsigned int features[] = {

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)