@@ -120,6 +120,9 @@ struct mlx5_vdpa_virtqueue {
120120 u16 avail_idx ;
121121 u16 used_idx ;
122122 int fw_state ;
123+
124+ u64 modified_fields ;
125+
123126 struct msi_map map ;
124127
125128 /* keep last in the struct */
@@ -1181,7 +1184,19 @@ static bool is_valid_state_change(int oldstate, int newstate)
11811184 }
11821185}
11831186
1184- static int modify_virtqueue (struct mlx5_vdpa_net * ndev , struct mlx5_vdpa_virtqueue * mvq , int state )
1187+ static bool modifiable_virtqueue_fields (struct mlx5_vdpa_virtqueue * mvq )
1188+ {
1189+ /* Only state is always modifiable */
1190+ if (mvq -> modified_fields & ~MLX5_VIRTQ_MODIFY_MASK_STATE )
1191+ return mvq -> fw_state == MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT ||
1192+ mvq -> fw_state == MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND ;
1193+
1194+ return true;
1195+ }
1196+
1197+ static int modify_virtqueue (struct mlx5_vdpa_net * ndev ,
1198+ struct mlx5_vdpa_virtqueue * mvq ,
1199+ int state )
11851200{
11861201 int inlen = MLX5_ST_SZ_BYTES (modify_virtio_net_q_in );
11871202 u32 out [MLX5_ST_SZ_DW (modify_virtio_net_q_out )] = {};
@@ -1193,6 +1208,9 @@ static int modify_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque
11931208 if (mvq -> fw_state == MLX5_VIRTIO_NET_Q_OBJECT_NONE )
11941209 return 0 ;
11951210
1211+ if (!modifiable_virtqueue_fields (mvq ))
1212+ return - EINVAL ;
1213+
11961214 if (!is_valid_state_change (mvq -> fw_state , state ))
11971215 return - EINVAL ;
11981216
@@ -1208,17 +1226,28 @@ static int modify_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque
12081226 MLX5_SET (general_obj_in_cmd_hdr , cmd_hdr , uid , ndev -> mvdev .res .uid );
12091227
12101228 obj_context = MLX5_ADDR_OF (modify_virtio_net_q_in , in , obj_context );
1211- MLX5_SET64 (virtio_net_q_object , obj_context , modify_field_select ,
1212- MLX5_VIRTQ_MODIFY_MASK_STATE );
1213- MLX5_SET (virtio_net_q_object , obj_context , state , state );
1229+ if (mvq -> modified_fields & MLX5_VIRTQ_MODIFY_MASK_STATE )
1230+ MLX5_SET (virtio_net_q_object , obj_context , state , state );
1231+
1232+ MLX5_SET64 (virtio_net_q_object , obj_context , modify_field_select , mvq -> modified_fields );
12141233 err = mlx5_cmd_exec (ndev -> mvdev .mdev , in , inlen , out , sizeof (out ));
12151234 kfree (in );
12161235 if (!err )
12171236 mvq -> fw_state = state ;
12181237
1238+ mvq -> modified_fields = 0 ;
1239+
12191240 return err ;
12201241}
12211242
1243+ static int modify_virtqueue_state (struct mlx5_vdpa_net * ndev ,
1244+ struct mlx5_vdpa_virtqueue * mvq ,
1245+ unsigned int state )
1246+ {
1247+ mvq -> modified_fields |= MLX5_VIRTQ_MODIFY_MASK_STATE ;
1248+ return modify_virtqueue (ndev , mvq , state );
1249+ }
1250+
12221251static int counter_set_alloc (struct mlx5_vdpa_net * ndev , struct mlx5_vdpa_virtqueue * mvq )
12231252{
12241253 u32 in [MLX5_ST_SZ_DW (create_virtio_q_counters_in )] = {};
@@ -1347,7 +1376,7 @@ static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
13471376 goto err_vq ;
13481377
13491378 if (mvq -> ready ) {
1350- err = modify_virtqueue (ndev , mvq , MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY );
1379+ err = modify_virtqueue_state (ndev , mvq , MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY );
13511380 if (err ) {
13521381 mlx5_vdpa_warn (& ndev -> mvdev , "failed to modify to ready vq idx %d(%d)\n" ,
13531382 idx , err );
@@ -1382,7 +1411,7 @@ static void suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *m
13821411 if (mvq -> fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY )
13831412 return ;
13841413
1385- if (modify_virtqueue (ndev , mvq , MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND ))
1414+ if (modify_virtqueue_state (ndev , mvq , MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND ))
13861415 mlx5_vdpa_warn (& ndev -> mvdev , "modify to suspend failed\n" );
13871416
13881417 if (query_virtqueue (ndev , mvq , & attr )) {
@@ -1407,6 +1436,7 @@ static void teardown_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *
14071436 return ;
14081437
14091438 suspend_vq (ndev , mvq );
1439+ mvq -> modified_fields = 0 ;
14101440 destroy_virtqueue (ndev , mvq );
14111441 dealloc_vector (ndev , mvq );
14121442 counter_set_dealloc (ndev , mvq );
@@ -2207,7 +2237,7 @@ static void mlx5_vdpa_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready
22072237 if (!ready ) {
22082238 suspend_vq (ndev , mvq );
22092239 } else {
2210- err = modify_virtqueue (ndev , mvq , MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY );
2240+ err = modify_virtqueue_state (ndev , mvq , MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY );
22112241 if (err ) {
22122242 mlx5_vdpa_warn (mvdev , "modify VQ %d to ready failed (%d)\n" , idx , err );
22132243 ready = false;
@@ -2804,8 +2834,10 @@ static void clear_vqs_ready(struct mlx5_vdpa_net *ndev)
28042834{
28052835 int i ;
28062836
2807- for (i = 0 ; i < ndev -> mvdev .max_vqs ; i ++ )
2837+ for (i = 0 ; i < ndev -> mvdev .max_vqs ; i ++ ) {
28082838 ndev -> vqs [i ].ready = false;
2839+ ndev -> vqs [i ].modified_fields = 0 ;
2840+ }
28092841
28102842 ndev -> mvdev .cvq .ready = false;
28112843}
0 commit comments