bool update_napi = false;
+ int ret, i, napi_weight;
+
+ if (queue >= vi->max_queue_pairs)
+ return -EINVAL;
/* Can't change NAPI weight if the link is up */
napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
- if (napi_weight ^ vi->sq[0].napi.weight) {
- if (dev->flags & IFF_UP)
- return -EBUSY;
- else
+ for (i = queue_number; i < queue_count; i++) {
+ if (napi_weight ^ vi->sq[i].napi.weight) {
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
update_napi = true;
+ /* All queues that belong to [queue_number, queue_count] will be
+ * updated for the sake of simplicity, which might not be necessary
+ */
+ queue_number = i;
+ break;
+ }
}
- if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL))
+ if (!per_queue && virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL))
ret = virtnet_send_notf_coal_cmds(vi, ec);
+ else if (per_queue && virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
+ ret = virtnet_send_notf_coal_vq_cmds(vi, ec, queue);
else
ret = virtnet_coal_params_supported(ec);
@@ -3118,7 +3188,7 @@ static int virtnet_set_coalesce_one(struct net_device *dev,
return ret;
if (update_napi) {
- for (i = 0; i < vi->max_queue_pairs; i++)
+ for (i = queue_number; i < queue_count; i++)
vi->sq[i].napi.weight = napi_weight;
}
@@ -3130,19 +3200,29 @@ static int virtnet_set_coalesce(struct net_device *dev,
struct kernel_ethtool_coalesce *kernel_coal,
struct netlink_ext_ack *extack)
{
- return virtnet_set_coalesce_one(dev, ec);
+ return virtnet_set_coalesce_one(dev, ec, false, 0);
}
static int virtnet_get_coalesce_one(struct net_device *dev,
- struct ethtool_coalesce *ec)
+ struct ethtool_coalesce *ec,
+ bool per_queue,
+ u32 queue)
{
struct virtnet_info *vi = netdev_priv(dev);
- if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
+ if (queue >= vi->max_queue_pairs)
+ return -EINVAL;
+
+ if (!per_queue && virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
ec->rx_coalesce_usecs = vi->intr_coal_rx.max_usecs;
ec->tx_coalesce_usecs = vi->intr_coal_tx.max_usecs;
ec->tx_max_coalesced_frames = vi->intr_coal_tx.max_packets;
ec->rx_max_coalesced_frames = vi->intr_coal_rx.max_packets;
+ } else if (per_queue && virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL)) {
+ ec->rx_coalesce_usecs = vi->rq[queue].intr_coal.max_usecs;
+ ec->tx_coalesce_usecs = vi->sq[queue].intr_coal.max_usecs;
+ ec->tx_max_coalesced_frames = vi->sq[queue].intr_coal.max_packets;
+ ec->rx_max_coalesced_frames = vi->rq[queue].intr_coal.max_packets;
} else {
ec->rx_max_coalesced_frames = 1;
@@ -3158,7 +3238,21 @@ static int virtnet_get_coalesce(struct net_device *dev,
struct kernel_ethtool_coalesce *kernel_coal,
struct netlink_ext_ack *extack)
{
- return virtnet_get_coalesce_one(dev, ec);
+ return virtnet_get_coalesce_one(dev, ec, false, 0);
+}
+
+static int virtnet_set_per_queue_coalesce(struct net_device *dev,
+ u32 queue,
+ struct ethtool_coalesce *ec)
+{
+ return virtnet_set_coalesce_one(dev, ec, true, queue);
+}
+
+static int virtnet_get_per_queue_coalesce(struct net_device *dev,
+ u32 queue,
+ struct ethtool_coalesce *ec)
+{
+ return virtnet_get_coalesce_one(dev, ec, true, queue);
}
static void virtnet_init_settings(struct net_device *dev)
@@ -3291,6 +3385,8 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
.set_link_ksettings = virtnet_set_link_ksettings,
.set_coalesce = virtnet_set_coalesce,
.get_coalesce = virtnet_get_coalesce,
+ .set_per_queue_coalesce = virtnet_set_per_queue_coalesce,
+ .get_per_queue_coalesce = virtnet_get_per_queue_coalesce,
.get_rxfh_key_size = virtnet_get_rxfh_key_size,
.get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
.get_rxfh = virtnet_get_rxfh,
diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h
index 12c1c9699935..cc65ef0f3c3e 100644
--- a/include/uapi/linux/virtio_net.h
+++ b/include/uapi/linux/virtio_net.h
@@ -56,6 +56,7 @@
#define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow
* Steering */
#define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */
+#define VIRTIO_NET_F_VQ_NOTF_COAL 52 /* Device supports virtqueue notification coalescing */
#define VIRTIO_NET_F_NOTF_COAL 53 /* Device supports notifications coalescing */
#define VIRTIO_NET_F_GUEST_USO4 54 /* Guest can handle USOv4 in. */
#define VIRTIO_NET_F_GUEST_USO6 55 /* Guest can handle USOv6 in. */
@@ -391,5 +392,18 @@ struct virtio_net_ctrl_coal_rx {
};
#define VIRTIO_NET_CTRL_NOTF_COAL_RX_SET 1
+#define VIRTIO_NET_CTRL_NOTF_COAL_VQ_SET 2
+#define VIRTIO_NET_CTRL_NOTF_COAL_VQ_GET 3
+
+struct virtio_net_ctrl_coal {
+ __le32 max_packets;
+ __le32 max_usecs;
+};
+
+struct virtio_net_ctrl_coal_vq {
+ __le16 vqn;
+ __le16 reserved;
+ struct virtio_net_ctrl_coal coal;
+};
#endif /* _UAPI_LINUX_VIRTIO_NET_H */
--
2.39.1