Skip to content

Commit bc9a2b3

Browse files
elic307imstsirkin
authored andcommitted
vdpa/mlx5: Support interrupt bypassing
Add support for generation of interrupts from the device directly to the VM to the VCPU thus avoiding the overhead on the host CPU. When supported, the driver will attempt to allocate vectors for each data virtqueue. If a vector for a virtqueue cannot be provided it will use the QP mode where notifications go through the driver. In addition, we add a shutdown callback to make sure allocated interrupts are released in case of shutdown to allow clean shutdown. Signed-off-by: Eli Cohen <elic@nvidia.com> Signed-off-by: Saeed Mahameed <saeedm@nvidia.com> Message-Id: <20230607190007.290505-1-dtatulea@nvidia.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent 33bd91f commit bc9a2b3

2 files changed

Lines changed: 171 additions & 9 deletions

File tree

drivers/vdpa/mlx5/net/mlx5_vnet.c

Lines changed: 156 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct mlx5_vq_restore_info {
8383
u64 driver_addr;
8484
u16 avail_index;
8585
u16 used_index;
86+
struct msi_map map;
8687
bool ready;
8788
bool restore;
8889
};
@@ -118,6 +119,7 @@ struct mlx5_vdpa_virtqueue {
118119
u16 avail_idx;
119120
u16 used_idx;
120121
int fw_state;
122+
struct msi_map map;
121123

122124
/* keep last in the struct */
123125
struct mlx5_vq_restore_info ri;
@@ -808,6 +810,13 @@ static bool counters_supported(const struct mlx5_vdpa_dev *mvdev)
808810
BIT_ULL(MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS);
809811
}
810812

813+
static bool msix_mode_supported(struct mlx5_vdpa_dev *mvdev)
814+
{
815+
return MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, event_mode) &
816+
(1 << MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE) &&
817+
pci_msix_can_alloc_dyn(mvdev->mdev->pdev);
818+
}
819+
811820
static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
812821
{
813822
int inlen = MLX5_ST_SZ_BYTES(create_virtio_net_q_in);
@@ -849,9 +858,15 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque
849858
if (vq_is_tx(mvq->index))
850859
MLX5_SET(virtio_net_q_object, obj_context, tisn_or_qpn, ndev->res.tisn);
851860

852-
MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_QP_MODE);
861+
if (mvq->map.virq) {
862+
MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE);
863+
MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->map.index);
864+
} else {
865+
MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_QP_MODE);
866+
MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->fwqp.mqp.qpn);
867+
}
868+
853869
MLX5_SET(virtio_q, vq_ctx, queue_index, mvq->index);
854-
MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->fwqp.mqp.qpn);
855870
MLX5_SET(virtio_q, vq_ctx, queue_size, mvq->num_ent);
856871
MLX5_SET(virtio_q, vq_ctx, virtio_version_1_0,
857872
!!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_F_VERSION_1)));
@@ -1194,6 +1209,56 @@ static void counter_set_dealloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_vir
11941209
mlx5_vdpa_warn(&ndev->mvdev, "dealloc counter set 0x%x\n", mvq->counter_set_id);
11951210
}
11961211

1212+
static irqreturn_t mlx5_vdpa_int_handler(int irq, void *priv)
1213+
{
1214+
struct vdpa_callback *cb = priv;
1215+
1216+
if (cb->callback)
1217+
return cb->callback(cb->private);
1218+
1219+
return IRQ_HANDLED;
1220+
}
1221+
1222+
static void alloc_vector(struct mlx5_vdpa_net *ndev,
1223+
struct mlx5_vdpa_virtqueue *mvq)
1224+
{
1225+
struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp;
1226+
struct mlx5_vdpa_irq_pool_entry *ent;
1227+
int err;
1228+
int i;
1229+
1230+
for (i = 0; i < irqp->num_ent; i++) {
1231+
ent = &irqp->entries[i];
1232+
if (!ent->used) {
1233+
snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d",
1234+
dev_name(&ndev->mvdev.vdev.dev), mvq->index);
1235+
ent->dev_id = &ndev->event_cbs[mvq->index];
1236+
err = request_irq(ent->map.virq, mlx5_vdpa_int_handler, 0,
1237+
ent->name, ent->dev_id);
1238+
if (err)
1239+
return;
1240+
1241+
ent->used = true;
1242+
mvq->map = ent->map;
1243+
return;
1244+
}
1245+
}
1246+
}
1247+
1248+
static void dealloc_vector(struct mlx5_vdpa_net *ndev,
1249+
struct mlx5_vdpa_virtqueue *mvq)
1250+
{
1251+
struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp;
1252+
int i;
1253+
1254+
for (i = 0; i < irqp->num_ent; i++)
1255+
if (mvq->map.virq == irqp->entries[i].map.virq) {
1256+
free_irq(mvq->map.virq, irqp->entries[i].dev_id);
1257+
irqp->entries[i].used = false;
1258+
return;
1259+
}
1260+
}
1261+
11971262
static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
11981263
{
11991264
u16 idx = mvq->index;
@@ -1223,27 +1288,31 @@ static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
12231288

12241289
err = counter_set_alloc(ndev, mvq);
12251290
if (err)
1226-
goto err_counter;
1291+
goto err_connect;
12271292

1293+
alloc_vector(ndev, mvq);
12281294
err = create_virtqueue(ndev, mvq);
12291295
if (err)
1230-
goto err_connect;
1296+
goto err_vq;
12311297

12321298
if (mvq->ready) {
12331299
err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY);
12341300
if (err) {
12351301
mlx5_vdpa_warn(&ndev->mvdev, "failed to modify to ready vq idx %d(%d)\n",
12361302
idx, err);
1237-
goto err_connect;
1303+
goto err_modify;
12381304
}
12391305
}
12401306

12411307
mvq->initialized = true;
12421308
return 0;
12431309

1244-
err_connect:
1310+
err_modify:
1311+
destroy_virtqueue(ndev, mvq);
1312+
err_vq:
1313+
dealloc_vector(ndev, mvq);
12451314
counter_set_dealloc(ndev, mvq);
1246-
err_counter:
1315+
err_connect:
12471316
qp_destroy(ndev, &mvq->vqqp);
12481317
err_vqqp:
12491318
qp_destroy(ndev, &mvq->fwqp);
@@ -1288,6 +1357,7 @@ static void teardown_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *
12881357

12891358
suspend_vq(ndev, mvq);
12901359
destroy_virtqueue(ndev, mvq);
1360+
dealloc_vector(ndev, mvq);
12911361
counter_set_dealloc(ndev, mvq);
12921362
qp_destroy(ndev, &mvq->vqqp);
12931363
qp_destroy(ndev, &mvq->fwqp);
@@ -2505,6 +2575,7 @@ static int save_channel_info(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqu
25052575
ri->desc_addr = mvq->desc_addr;
25062576
ri->device_addr = mvq->device_addr;
25072577
ri->driver_addr = mvq->driver_addr;
2578+
ri->map = mvq->map;
25082579
ri->restore = true;
25092580
return 0;
25102581
}
@@ -2549,6 +2620,7 @@ static void restore_channels_info(struct mlx5_vdpa_net *ndev)
25492620
mvq->desc_addr = ri->desc_addr;
25502621
mvq->device_addr = ri->device_addr;
25512622
mvq->driver_addr = ri->driver_addr;
2623+
mvq->map = ri->map;
25522624
}
25532625
}
25542626

@@ -2833,6 +2905,25 @@ static struct device *mlx5_get_vq_dma_dev(struct vdpa_device *vdev, u16 idx)
28332905
return mvdev->vdev.dma_dev;
28342906
}
28352907

2908+
static void free_irqs(struct mlx5_vdpa_net *ndev)
2909+
{
2910+
struct mlx5_vdpa_irq_pool_entry *ent;
2911+
int i;
2912+
2913+
if (!msix_mode_supported(&ndev->mvdev))
2914+
return;
2915+
2916+
if (!ndev->irqp.entries)
2917+
return;
2918+
2919+
for (i = ndev->irqp.num_ent - 1; i >= 0; i--) {
2920+
ent = ndev->irqp.entries + i;
2921+
if (ent->map.virq)
2922+
pci_msix_free_irq(ndev->mvdev.mdev->pdev, ent->map);
2923+
}
2924+
kfree(ndev->irqp.entries);
2925+
}
2926+
28362927
static void mlx5_vdpa_free(struct vdpa_device *vdev)
28372928
{
28382929
struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
@@ -2848,6 +2939,7 @@ static void mlx5_vdpa_free(struct vdpa_device *vdev)
28482939
mlx5_mpfs_del_mac(pfmdev, ndev->config.mac);
28492940
}
28502941
mlx5_vdpa_free_resources(&ndev->mvdev);
2942+
free_irqs(ndev);
28512943
kfree(ndev->event_cbs);
28522944
kfree(ndev->vqs);
28532945
}
@@ -2876,9 +2968,23 @@ static struct vdpa_notification_area mlx5_get_vq_notification(struct vdpa_device
28762968
return ret;
28772969
}
28782970

2879-
static int mlx5_get_vq_irq(struct vdpa_device *vdv, u16 idx)
2971+
static int mlx5_get_vq_irq(struct vdpa_device *vdev, u16 idx)
28802972
{
2881-
return -EOPNOTSUPP;
2973+
struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
2974+
struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
2975+
struct mlx5_vdpa_virtqueue *mvq;
2976+
2977+
if (!is_index_valid(mvdev, idx))
2978+
return -EINVAL;
2979+
2980+
if (is_ctrl_vq_idx(mvdev, idx))
2981+
return -EOPNOTSUPP;
2982+
2983+
mvq = &ndev->vqs[idx];
2984+
if (!mvq->map.virq)
2985+
return -EOPNOTSUPP;
2986+
2987+
return mvq->map.virq;
28822988
}
28832989

28842990
static u64 mlx5_vdpa_get_driver_features(struct vdpa_device *vdev)
@@ -3155,6 +3261,34 @@ static int config_func_mtu(struct mlx5_core_dev *mdev, u16 mtu)
31553261
return err;
31563262
}
31573263

3264+
static void allocate_irqs(struct mlx5_vdpa_net *ndev)
3265+
{
3266+
struct mlx5_vdpa_irq_pool_entry *ent;
3267+
int i;
3268+
3269+
if (!msix_mode_supported(&ndev->mvdev))
3270+
return;
3271+
3272+
if (!ndev->mvdev.mdev->pdev)
3273+
return;
3274+
3275+
ndev->irqp.entries = kcalloc(ndev->mvdev.max_vqs, sizeof(*ndev->irqp.entries), GFP_KERNEL);
3276+
if (!ndev->irqp.entries)
3277+
return;
3278+
3279+
3280+
for (i = 0; i < ndev->mvdev.max_vqs; i++) {
3281+
ent = ndev->irqp.entries + i;
3282+
snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d",
3283+
dev_name(&ndev->mvdev.vdev.dev), i);
3284+
ent->map = pci_msix_alloc_irq_at(ndev->mvdev.mdev->pdev, MSI_ANY_INDEX, NULL);
3285+
if (!ent->map.virq)
3286+
return;
3287+
3288+
ndev->irqp.num_ent++;
3289+
}
3290+
}
3291+
31583292
static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
31593293
const struct vdpa_dev_set_config *add_config)
31603294
{
@@ -3233,6 +3367,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
32333367
}
32343368

32353369
init_mvqs(ndev);
3370+
allocate_irqs(ndev);
32363371
init_rwsem(&ndev->reslock);
32373372
config = &ndev->config;
32383373

@@ -3413,6 +3548,17 @@ static void mlx5v_remove(struct auxiliary_device *adev)
34133548
kfree(mgtdev);
34143549
}
34153550

3551+
static void mlx5v_shutdown(struct auxiliary_device *auxdev)
3552+
{
3553+
struct mlx5_vdpa_mgmtdev *mgtdev;
3554+
struct mlx5_vdpa_net *ndev;
3555+
3556+
mgtdev = auxiliary_get_drvdata(auxdev);
3557+
ndev = mgtdev->ndev;
3558+
3559+
free_irqs(ndev);
3560+
}
3561+
34163562
static const struct auxiliary_device_id mlx5v_id_table[] = {
34173563
{ .name = MLX5_ADEV_NAME ".vnet", },
34183564
{},
@@ -3424,6 +3570,7 @@ static struct auxiliary_driver mlx5v_driver = {
34243570
.name = "vnet",
34253571
.probe = mlx5v_probe,
34263572
.remove = mlx5v_remove,
3573+
.shutdown = mlx5v_shutdown,
34273574
.id_table = mlx5v_id_table,
34283575
};
34293576

drivers/vdpa/mlx5/net/mlx5_vnet.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ static inline u16 key2vid(u64 key)
2626
return (u16)(key >> 48) & 0xfff;
2727
}
2828

29+
#define MLX5_VDPA_IRQ_NAME_LEN 32
30+
31+
struct mlx5_vdpa_irq_pool_entry {
32+
struct msi_map map;
33+
bool used;
34+
char name[MLX5_VDPA_IRQ_NAME_LEN];
35+
void *dev_id;
36+
};
37+
38+
struct mlx5_vdpa_irq_pool {
39+
int num_ent;
40+
struct mlx5_vdpa_irq_pool_entry *entries;
41+
};
42+
2943
struct mlx5_vdpa_net {
3044
struct mlx5_vdpa_dev mvdev;
3145
struct mlx5_vdpa_net_resources res;
@@ -49,6 +63,7 @@ struct mlx5_vdpa_net {
4963
struct vdpa_callback config_cb;
5064
struct mlx5_vdpa_wq_ent cvq_ent;
5165
struct hlist_head macvlan_hash[MLX5V_MACVLAN_SIZE];
66+
struct mlx5_vdpa_irq_pool irqp;
5267
struct dentry *debugfs;
5368
};
5469

0 commit comments

Comments
 (0)