@@ -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
217222struct 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+
30813135static 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+
30963162static 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+
31523283static 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 ,
0 commit comments