@@ -133,7 +133,7 @@ struct mlx5_vdpa_virtqueue {
133133/* We will remove this limitation once mlx5_vdpa_alloc_resources()
134134 * provides for driver space allocation
135135 */
136- #define MLX5_MAX_SUPPORTED_VQS 2
136+ #define MLX5_MAX_SUPPORTED_VQS 16
137137
138138static bool is_index_valid (struct mlx5_vdpa_dev * mvdev , u16 idx )
139139{
@@ -184,13 +184,33 @@ static bool mlx5_vdpa_debug;
184184 mlx5_vdpa_info(mvdev, "%s\n", #_status); \
185185 } while (0)
186186
187+ /* TODO: cross-endian support */
188+ static inline bool mlx5_vdpa_is_little_endian (struct mlx5_vdpa_dev * mvdev )
189+ {
190+ return virtio_legacy_is_little_endian () ||
191+ (mvdev -> actual_features & BIT_ULL (VIRTIO_F_VERSION_1 ));
192+ }
193+
194+ static u16 mlx5vdpa16_to_cpu (struct mlx5_vdpa_dev * mvdev , __virtio16 val )
195+ {
196+ return __virtio16_to_cpu (mlx5_vdpa_is_little_endian (mvdev ), val );
197+ }
198+
199+ static __virtio16 cpu_to_mlx5vdpa16 (struct mlx5_vdpa_dev * mvdev , u16 val )
200+ {
201+ return __cpu_to_virtio16 (mlx5_vdpa_is_little_endian (mvdev ), val );
202+ }
203+
187204static inline u32 mlx5_vdpa_max_qps (int max_vqs )
188205{
189206 return max_vqs / 2 ;
190207}
191208
192209static u16 ctrl_vq_idx (struct mlx5_vdpa_dev * mvdev )
193210{
211+ if (!(mvdev -> actual_features & BIT_ULL (VIRTIO_NET_F_MQ )))
212+ return 2 ;
213+
194214 return 2 * mlx5_vdpa_max_qps (mvdev -> max_vqs );
195215}
196216
@@ -1126,10 +1146,8 @@ static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
11261146 if (!mvq -> num_ent )
11271147 return 0 ;
11281148
1129- if (mvq -> initialized ) {
1130- mlx5_vdpa_warn (& ndev -> mvdev , "attempt re init\n" );
1131- return - EINVAL ;
1132- }
1149+ if (mvq -> initialized )
1150+ return 0 ;
11331151
11341152 err = cq_create (ndev , idx , mvq -> num_ent );
11351153 if (err )
@@ -1216,19 +1234,20 @@ static void teardown_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *
12161234
12171235static int create_rqt (struct mlx5_vdpa_net * ndev )
12181236{
1219- int log_max_rqt ;
12201237 __be32 * list ;
1238+ int max_rqt ;
12211239 void * rqtc ;
12221240 int inlen ;
12231241 void * in ;
12241242 int i , j ;
12251243 int err ;
12261244
1227- log_max_rqt = min_t (int , 1 , MLX5_CAP_GEN (ndev -> mvdev .mdev , log_max_rqt_size ));
1228- if (log_max_rqt < 1 )
1245+ max_rqt = min_t (int , MLX5_MAX_SUPPORTED_VQS / 2 ,
1246+ 1 << MLX5_CAP_GEN (ndev -> mvdev .mdev , log_max_rqt_size ));
1247+ if (max_rqt < 1 )
12291248 return - EOPNOTSUPP ;
12301249
1231- inlen = MLX5_ST_SZ_BYTES (create_rqt_in ) + ( 1 << log_max_rqt ) * MLX5_ST_SZ_BYTES (rq_num );
1250+ inlen = MLX5_ST_SZ_BYTES (create_rqt_in ) + max_rqt * MLX5_ST_SZ_BYTES (rq_num );
12321251 in = kzalloc (inlen , GFP_KERNEL );
12331252 if (!in )
12341253 return - ENOMEM ;
@@ -1237,10 +1256,9 @@ static int create_rqt(struct mlx5_vdpa_net *ndev)
12371256 rqtc = MLX5_ADDR_OF (create_rqt_in , in , rqt_context );
12381257
12391258 MLX5_SET (rqtc , rqtc , list_q_type , MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q );
1240- MLX5_SET (rqtc , rqtc , rqt_max_size , 1 << log_max_rqt );
1241- MLX5_SET (rqtc , rqtc , rqt_actual_size , 1 );
1259+ MLX5_SET (rqtc , rqtc , rqt_max_size , max_rqt );
12421260 list = MLX5_ADDR_OF (rqtc , rqtc , rq_num [0 ]);
1243- for (i = 0 , j = 0 ; j < ndev -> mvdev . max_vqs ; j ++ ) {
1261+ for (i = 0 , j = 0 ; j < max_rqt ; j ++ ) {
12441262 if (!ndev -> vqs [j ].initialized )
12451263 continue ;
12461264
@@ -1249,6 +1267,7 @@ static int create_rqt(struct mlx5_vdpa_net *ndev)
12491267 i ++ ;
12501268 }
12511269 }
1270+ MLX5_SET (rqtc , rqtc , rqt_actual_size , i );
12521271
12531272 err = mlx5_vdpa_create_rqt (& ndev -> mvdev , in , inlen , & ndev -> res .rqtn );
12541273 kfree (in );
@@ -1258,6 +1277,52 @@ static int create_rqt(struct mlx5_vdpa_net *ndev)
12581277 return 0 ;
12591278}
12601279
1280+ #define MLX5_MODIFY_RQT_NUM_RQS ((u64)1)
1281+
1282+ static int modify_rqt (struct mlx5_vdpa_net * ndev , int num )
1283+ {
1284+ __be32 * list ;
1285+ int max_rqt ;
1286+ void * rqtc ;
1287+ int inlen ;
1288+ void * in ;
1289+ int i , j ;
1290+ int err ;
1291+
1292+ max_rqt = min_t (int , ndev -> cur_num_vqs / 2 ,
1293+ 1 << MLX5_CAP_GEN (ndev -> mvdev .mdev , log_max_rqt_size ));
1294+ if (max_rqt < 1 )
1295+ return - EOPNOTSUPP ;
1296+
1297+ inlen = MLX5_ST_SZ_BYTES (modify_rqt_in ) + max_rqt * MLX5_ST_SZ_BYTES (rq_num );
1298+ in = kzalloc (inlen , GFP_KERNEL );
1299+ if (!in )
1300+ return - ENOMEM ;
1301+
1302+ MLX5_SET (modify_rqt_in , in , uid , ndev -> mvdev .res .uid );
1303+ MLX5_SET64 (modify_rqt_in , in , bitmask , MLX5_MODIFY_RQT_NUM_RQS );
1304+ rqtc = MLX5_ADDR_OF (modify_rqt_in , in , ctx );
1305+ MLX5_SET (rqtc , rqtc , list_q_type , MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q );
1306+
1307+ list = MLX5_ADDR_OF (rqtc , rqtc , rq_num [0 ]);
1308+ for (i = 0 , j = 0 ; j < num ; j ++ ) {
1309+ if (!ndev -> vqs [j ].initialized )
1310+ continue ;
1311+
1312+ if (!vq_is_tx (ndev -> vqs [j ].index )) {
1313+ list [i ] = cpu_to_be32 (ndev -> vqs [j ].virtq_id );
1314+ i ++ ;
1315+ }
1316+ }
1317+ MLX5_SET (rqtc , rqtc , rqt_actual_size , i );
1318+ err = mlx5_vdpa_modify_rqt (& ndev -> mvdev , in , inlen , ndev -> res .rqtn );
1319+ kfree (in );
1320+ if (err )
1321+ return err ;
1322+
1323+ return 0 ;
1324+ }
1325+
12611326static void destroy_rqt (struct mlx5_vdpa_net * ndev )
12621327{
12631328 mlx5_vdpa_destroy_rqt (& ndev -> mvdev , ndev -> res .rqtn );
@@ -1417,6 +1482,77 @@ static virtio_net_ctrl_ack handle_ctrl_mac(struct mlx5_vdpa_dev *mvdev, u8 cmd)
14171482 return status ;
14181483}
14191484
1485+ static int change_num_qps (struct mlx5_vdpa_dev * mvdev , int newqps )
1486+ {
1487+ struct mlx5_vdpa_net * ndev = to_mlx5_vdpa_ndev (mvdev );
1488+ int cur_qps = ndev -> cur_num_vqs / 2 ;
1489+ int err ;
1490+ int i ;
1491+
1492+ if (cur_qps > newqps ) {
1493+ err = modify_rqt (ndev , 2 * newqps );
1494+ if (err )
1495+ return err ;
1496+
1497+ for (i = ndev -> cur_num_vqs - 1 ; i >= 2 * newqps ; i -- )
1498+ teardown_vq (ndev , & ndev -> vqs [i ]);
1499+
1500+ ndev -> cur_num_vqs = 2 * newqps ;
1501+ } else {
1502+ ndev -> cur_num_vqs = 2 * newqps ;
1503+ for (i = cur_qps * 2 ; i < 2 * newqps ; i ++ ) {
1504+ err = setup_vq (ndev , & ndev -> vqs [i ]);
1505+ if (err )
1506+ goto clean_added ;
1507+ }
1508+ err = modify_rqt (ndev , 2 * newqps );
1509+ if (err )
1510+ goto clean_added ;
1511+ }
1512+ return 0 ;
1513+
1514+ clean_added :
1515+ for (-- i ; i >= cur_qps ; -- i )
1516+ teardown_vq (ndev , & ndev -> vqs [i ]);
1517+
1518+ return err ;
1519+ }
1520+
1521+ static virtio_net_ctrl_ack handle_ctrl_mq (struct mlx5_vdpa_dev * mvdev , u8 cmd )
1522+ {
1523+ struct mlx5_vdpa_net * ndev = to_mlx5_vdpa_ndev (mvdev );
1524+ virtio_net_ctrl_ack status = VIRTIO_NET_ERR ;
1525+ struct mlx5_control_vq * cvq = & mvdev -> cvq ;
1526+ struct virtio_net_ctrl_mq mq ;
1527+ size_t read ;
1528+ u16 newqps ;
1529+
1530+ switch (cmd ) {
1531+ case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET :
1532+ read = vringh_iov_pull_iotlb (& cvq -> vring , & cvq -> riov , (void * )& mq , sizeof (mq ));
1533+ if (read != sizeof (mq ))
1534+ break ;
1535+
1536+ newqps = mlx5vdpa16_to_cpu (mvdev , mq .virtqueue_pairs );
1537+ if (ndev -> cur_num_vqs == 2 * newqps ) {
1538+ status = VIRTIO_NET_OK ;
1539+ break ;
1540+ }
1541+
1542+ if (newqps & (newqps - 1 ))
1543+ break ;
1544+
1545+ if (!change_num_qps (mvdev , newqps ))
1546+ status = VIRTIO_NET_OK ;
1547+
1548+ break ;
1549+ default :
1550+ break ;
1551+ }
1552+
1553+ return status ;
1554+ }
1555+
14201556static void mlx5_cvq_kick_handler (struct work_struct * work )
14211557{
14221558 virtio_net_ctrl_ack status = VIRTIO_NET_ERR ;
@@ -1452,6 +1588,9 @@ static void mlx5_cvq_kick_handler(struct work_struct *work)
14521588 case VIRTIO_NET_CTRL_MAC :
14531589 status = handle_ctrl_mac (mvdev , ctrl .cmd );
14541590 break ;
1591+ case VIRTIO_NET_CTRL_MQ :
1592+ status = handle_ctrl_mq (mvdev , ctrl .cmd );
1593+ break ;
14551594
14561595 default :
14571596 break ;
@@ -1709,6 +1848,7 @@ static u64 mlx5_vdpa_get_features(struct vdpa_device *vdev)
17091848 ndev -> mvdev .mlx_features |= BIT_ULL (VIRTIO_F_ACCESS_PLATFORM );
17101849 ndev -> mvdev .mlx_features |= BIT_ULL (VIRTIO_NET_F_CTRL_VQ );
17111850 ndev -> mvdev .mlx_features |= BIT_ULL (VIRTIO_NET_F_CTRL_MAC_ADDR );
1851+ ndev -> mvdev .mlx_features |= BIT_ULL (VIRTIO_NET_F_MQ );
17121852
17131853 print_features (mvdev , ndev -> mvdev .mlx_features , false);
17141854 return ndev -> mvdev .mlx_features ;
@@ -1768,18 +1908,6 @@ static void teardown_virtqueues(struct mlx5_vdpa_net *ndev)
17681908 }
17691909}
17701910
1771- /* TODO: cross-endian support */
1772- static inline bool mlx5_vdpa_is_little_endian (struct mlx5_vdpa_dev * mvdev )
1773- {
1774- return virtio_legacy_is_little_endian () ||
1775- (mvdev -> actual_features & BIT_ULL (VIRTIO_F_VERSION_1 ));
1776- }
1777-
1778- static __virtio16 cpu_to_mlx5vdpa16 (struct mlx5_vdpa_dev * mvdev , u16 val )
1779- {
1780- return __cpu_to_virtio16 (mlx5_vdpa_is_little_endian (mvdev ), val );
1781- }
1782-
17831911static void update_cvq_info (struct mlx5_vdpa_dev * mvdev )
17841912{
17851913 if (MLX5_FEATURE (mvdev , VIRTIO_NET_F_CTRL_VQ )) {
@@ -1851,15 +1979,14 @@ static u8 mlx5_vdpa_get_status(struct vdpa_device *vdev)
18511979static int save_channel_info (struct mlx5_vdpa_net * ndev , struct mlx5_vdpa_virtqueue * mvq )
18521980{
18531981 struct mlx5_vq_restore_info * ri = & mvq -> ri ;
1854- struct mlx5_virtq_attr attr ;
1982+ struct mlx5_virtq_attr attr = {} ;
18551983 int err ;
18561984
1857- if (!mvq -> initialized )
1858- return 0 ;
1859-
1860- err = query_virtqueue (ndev , mvq , & attr );
1861- if (err )
1862- return err ;
1985+ if (mvq -> initialized ) {
1986+ err = query_virtqueue (ndev , mvq , & attr );
1987+ if (err )
1988+ return err ;
1989+ }
18631990
18641991 ri -> avail_index = attr .available_index ;
18651992 ri -> used_index = attr .used_index ;
0 commit comments