Skip to content

Commit 5289373

Browse files
elic307imstsirkin
authored andcommitted
vdpa/mlx5: Add multiqueue support
Multiqueue support requires additional virtio_net_q objects to be added or removed per the configured number of queue pairs. In addition the RQ tables needs to be modified to match the number of configured receive queues so the packets are dispatched to the right virtqueue according to the hash result. Note: qemu v6.0.0 is broken when the device requests more than two data queues; no net device will be created for the vdpa device. To avoid this, one should specify mq=off to qemu. In this case it will end up with a single queue. Signed-off-by: Eli Cohen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent 5262912 commit 5289373

File tree

3 files changed

+169
-31
lines changed

3 files changed

+169
-31
lines changed

drivers/vdpa/mlx5/core/mlx5_vdpa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ int mlx5_vdpa_get_null_mkey(struct mlx5_vdpa_dev *dev, u32 *null_mkey);
9191
int mlx5_vdpa_create_tis(struct mlx5_vdpa_dev *mvdev, void *in, u32 *tisn);
9292
void mlx5_vdpa_destroy_tis(struct mlx5_vdpa_dev *mvdev, u32 tisn);
9393
int mlx5_vdpa_create_rqt(struct mlx5_vdpa_dev *mvdev, void *in, int inlen, u32 *rqtn);
94+
int mlx5_vdpa_modify_rqt(struct mlx5_vdpa_dev *mvdev, void *in, int inlen, u32 rqtn);
9495
void mlx5_vdpa_destroy_rqt(struct mlx5_vdpa_dev *mvdev, u32 rqtn);
9596
int mlx5_vdpa_create_tir(struct mlx5_vdpa_dev *mvdev, void *in, u32 *tirn);
9697
void mlx5_vdpa_destroy_tir(struct mlx5_vdpa_dev *mvdev, u32 tirn);

drivers/vdpa/mlx5/core/resources.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,16 @@ int mlx5_vdpa_create_rqt(struct mlx5_vdpa_dev *mvdev, void *in, int inlen, u32 *
129129
return err;
130130
}
131131

132+
int mlx5_vdpa_modify_rqt(struct mlx5_vdpa_dev *mvdev, void *in, int inlen, u32 rqtn)
133+
{
134+
u32 out[MLX5_ST_SZ_DW(create_rqt_out)] = {};
135+
136+
MLX5_SET(modify_rqt_in, in, uid, mvdev->res.uid);
137+
MLX5_SET(modify_rqt_in, in, rqtn, rqtn);
138+
MLX5_SET(modify_rqt_in, in, opcode, MLX5_CMD_OP_MODIFY_RQT);
139+
return mlx5_cmd_exec(mvdev->mdev, in, inlen, out, sizeof(out));
140+
}
141+
132142
void mlx5_vdpa_destroy_rqt(struct mlx5_vdpa_dev *mvdev, u32 rqtn)
133143
{
134144
u32 in[MLX5_ST_SZ_DW(destroy_rqt_in)] = {};

drivers/vdpa/mlx5/net/mlx5_vnet.c

Lines changed: 158 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -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

138138
static 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+
187204
static inline u32 mlx5_vdpa_max_qps(int max_vqs)
188205
{
189206
return max_vqs / 2;
190207
}
191208

192209
static 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

12171235
static 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+
12611326
static 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+
14201556
static 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-
17831911
static 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)
18511979
static 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

Comments
 (0)