@@ -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 */
130135struct 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
212222struct 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+
30933162static 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
43814520static unsigned int features [] = {
0 commit comments