Skip to content

Commit fd27ef6

Browse files
Feng LiuAlex Williamson
authored andcommitted
virtio-pci: Introduce admin virtqueue
Introduce support for the admin virtqueue. By negotiating VIRTIO_F_ADMIN_VQ feature, driver detects capability and creates one administration virtqueue. Administration virtqueue implementation in virtio pci generic layer, enables multiple types of upper layer drivers such as vfio, net, blk to utilize it. Signed-off-by: Feng Liu <feliu@nvidia.com> Reviewed-by: Parav Pandit <parav@nvidia.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Yishai Hadas <yishaih@nvidia.com> Link: https://lore.kernel.org/r/20231219093247.170936-3-yishaih@nvidia.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent 838bebb commit fd27ef6

8 files changed

Lines changed: 157 additions & 8 deletions

File tree

drivers/virtio/virtio.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,15 @@ static int virtio_dev_probe(struct device *_d)
302302
if (err)
303303
goto err;
304304

305+
if (dev->config->create_avq) {
306+
err = dev->config->create_avq(dev);
307+
if (err)
308+
goto err;
309+
}
310+
305311
err = drv->probe(dev);
306312
if (err)
307-
goto err;
313+
goto err_probe;
308314

309315
/* If probe didn't do it, mark device DRIVER_OK ourselves. */
310316
if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK))
@@ -316,6 +322,10 @@ static int virtio_dev_probe(struct device *_d)
316322
virtio_config_enable(dev);
317323

318324
return 0;
325+
326+
err_probe:
327+
if (dev->config->destroy_avq)
328+
dev->config->destroy_avq(dev);
319329
err:
320330
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
321331
return err;
@@ -331,6 +341,9 @@ static void virtio_dev_remove(struct device *_d)
331341

332342
drv->remove(dev);
333343

344+
if (dev->config->destroy_avq)
345+
dev->config->destroy_avq(dev);
346+
334347
/* Driver should have reset device. */
335348
WARN_ON_ONCE(dev->config->get_status(dev));
336349

@@ -489,13 +502,20 @@ EXPORT_SYMBOL_GPL(unregister_virtio_device);
489502
int virtio_device_freeze(struct virtio_device *dev)
490503
{
491504
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
505+
int ret;
492506

493507
virtio_config_disable(dev);
494508

495509
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
496510

497-
if (drv && drv->freeze)
498-
return drv->freeze(dev);
511+
if (drv && drv->freeze) {
512+
ret = drv->freeze(dev);
513+
if (ret)
514+
return ret;
515+
}
516+
517+
if (dev->config->destroy_avq)
518+
dev->config->destroy_avq(dev);
499519

500520
return 0;
501521
}
@@ -532,10 +552,16 @@ int virtio_device_restore(struct virtio_device *dev)
532552
if (ret)
533553
goto err;
534554

555+
if (dev->config->create_avq) {
556+
ret = dev->config->create_avq(dev);
557+
if (ret)
558+
goto err;
559+
}
560+
535561
if (drv->restore) {
536562
ret = drv->restore(dev);
537563
if (ret)
538-
goto err;
564+
goto err_restore;
539565
}
540566

541567
/* If restore didn't do it, mark device DRIVER_OK ourselves. */
@@ -546,6 +572,9 @@ int virtio_device_restore(struct virtio_device *dev)
546572

547573
return 0;
548574

575+
err_restore:
576+
if (dev->config->destroy_avq)
577+
dev->config->destroy_avq(dev);
549578
err:
550579
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
551580
return ret;

drivers/virtio/virtio_pci_common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ void vp_del_vqs(struct virtio_device *vdev)
236236
int i;
237237

238238
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
239+
if (vp_dev->is_avq(vdev, vq->index))
240+
continue;
241+
239242
if (vp_dev->per_vq_vectors) {
240243
int v = vp_dev->vqs[vq->index]->msix_vector;
241244

drivers/virtio/virtio_pci_common.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ struct virtio_pci_vq_info {
4141
unsigned int msix_vector;
4242
};
4343

44+
struct virtio_pci_admin_vq {
45+
/* Virtqueue info associated with this admin queue. */
46+
struct virtio_pci_vq_info info;
47+
/* Name of the admin queue: avq.$vq_index. */
48+
char name[10];
49+
u16 vq_index;
50+
};
51+
4452
/* Our device structure */
4553
struct virtio_pci_device {
4654
struct virtio_device vdev;
@@ -58,9 +66,13 @@ struct virtio_pci_device {
5866
spinlock_t lock;
5967
struct list_head virtqueues;
6068

61-
/* array of all queues for house-keeping */
69+
/* Array of all virtqueues reported in the
70+
* PCI common config num_queues field
71+
*/
6272
struct virtio_pci_vq_info **vqs;
6373

74+
struct virtio_pci_admin_vq admin_vq;
75+
6476
/* MSI-X support */
6577
int msix_enabled;
6678
int intx_enabled;
@@ -86,6 +98,7 @@ struct virtio_pci_device {
8698
void (*del_vq)(struct virtio_pci_vq_info *info);
8799

88100
u16 (*config_vector)(struct virtio_pci_device *vp_dev, u16 vector);
101+
bool (*is_avq)(struct virtio_device *vdev, unsigned int index);
89102
};
90103

91104
/* Constants for MSI-X */

drivers/virtio/virtio_pci_modern.c

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,25 @@
1919
#define VIRTIO_RING_NO_LEGACY
2020
#include "virtio_pci_common.h"
2121

22+
#define VIRTIO_AVQ_SGS_MAX 4
23+
2224
static u64 vp_get_features(struct virtio_device *vdev)
2325
{
2426
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
2527

2628
return vp_modern_get_features(&vp_dev->mdev);
2729
}
2830

31+
static bool vp_is_avq(struct virtio_device *vdev, unsigned int index)
32+
{
33+
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
34+
35+
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
36+
return false;
37+
38+
return index == vp_dev->admin_vq.vq_index;
39+
}
40+
2941
static void vp_transport_features(struct virtio_device *vdev, u64 features)
3042
{
3143
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
@@ -37,6 +49,9 @@ static void vp_transport_features(struct virtio_device *vdev, u64 features)
3749

3850
if (features & BIT_ULL(VIRTIO_F_RING_RESET))
3951
__virtio_set_bit(vdev, VIRTIO_F_RING_RESET);
52+
53+
if (features & BIT_ULL(VIRTIO_F_ADMIN_VQ))
54+
__virtio_set_bit(vdev, VIRTIO_F_ADMIN_VQ);
4055
}
4156

4257
static int __vp_check_common_size_one_feature(struct virtio_device *vdev, u32 fbit,
@@ -69,6 +84,9 @@ static int vp_check_common_size(struct virtio_device *vdev)
6984
if (vp_check_common_size_one_feature(vdev, VIRTIO_F_RING_RESET, queue_reset))
7085
return -EINVAL;
7186

87+
if (vp_check_common_size_one_feature(vdev, VIRTIO_F_ADMIN_VQ, admin_queue_num))
88+
return -EINVAL;
89+
7290
return 0;
7391
}
7492

@@ -345,6 +363,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
345363
struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
346364
bool (*notify)(struct virtqueue *vq);
347365
struct virtqueue *vq;
366+
bool is_avq;
348367
u16 num;
349368
int err;
350369

@@ -353,11 +372,13 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
353372
else
354373
notify = vp_notify;
355374

356-
if (index >= vp_modern_get_num_queues(mdev))
375+
is_avq = vp_is_avq(&vp_dev->vdev, index);
376+
if (index >= vp_modern_get_num_queues(mdev) && !is_avq)
357377
return ERR_PTR(-EINVAL);
358378

379+
num = is_avq ?
380+
VIRTIO_AVQ_SGS_MAX : vp_modern_get_queue_size(mdev, index);
359381
/* Check if queue is either not available or already active. */
360-
num = vp_modern_get_queue_size(mdev, index);
361382
if (!num || vp_modern_get_queue_enable(mdev, index))
362383
return ERR_PTR(-ENOENT);
363384

@@ -383,6 +404,9 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
383404
goto err;
384405
}
385406

407+
if (is_avq)
408+
vp_dev->admin_vq.info.vq = vq;
409+
386410
return vq;
387411

388412
err:
@@ -418,6 +442,9 @@ static void del_vq(struct virtio_pci_vq_info *info)
418442
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
419443
struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
420444

445+
if (vp_is_avq(&vp_dev->vdev, vq->index))
446+
vp_dev->admin_vq.info.vq = NULL;
447+
421448
if (vp_dev->msix_enabled)
422449
vp_modern_queue_vector(mdev, vq->index,
423450
VIRTIO_MSI_NO_VECTOR);
@@ -527,6 +554,45 @@ static bool vp_get_shm_region(struct virtio_device *vdev,
527554
return true;
528555
}
529556

557+
static int vp_modern_create_avq(struct virtio_device *vdev)
558+
{
559+
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
560+
struct virtio_pci_admin_vq *avq;
561+
struct virtqueue *vq;
562+
u16 admin_q_num;
563+
564+
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
565+
return 0;
566+
567+
admin_q_num = vp_modern_avq_num(&vp_dev->mdev);
568+
if (!admin_q_num)
569+
return -EINVAL;
570+
571+
avq = &vp_dev->admin_vq;
572+
avq->vq_index = vp_modern_avq_index(&vp_dev->mdev);
573+
sprintf(avq->name, "avq.%u", avq->vq_index);
574+
vq = vp_dev->setup_vq(vp_dev, &vp_dev->admin_vq.info, avq->vq_index, NULL,
575+
avq->name, NULL, VIRTIO_MSI_NO_VECTOR);
576+
if (IS_ERR(vq)) {
577+
dev_err(&vdev->dev, "failed to setup admin virtqueue, err=%ld",
578+
PTR_ERR(vq));
579+
return PTR_ERR(vq);
580+
}
581+
582+
vp_modern_set_queue_enable(&vp_dev->mdev, avq->info.vq->index, true);
583+
return 0;
584+
}
585+
586+
static void vp_modern_destroy_avq(struct virtio_device *vdev)
587+
{
588+
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
589+
590+
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
591+
return;
592+
593+
vp_dev->del_vq(&vp_dev->admin_vq.info);
594+
}
595+
530596
static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
531597
.get = NULL,
532598
.set = NULL,
@@ -545,6 +611,8 @@ static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
545611
.get_shm_region = vp_get_shm_region,
546612
.disable_vq_and_reset = vp_modern_disable_vq_and_reset,
547613
.enable_vq_after_reset = vp_modern_enable_vq_after_reset,
614+
.create_avq = vp_modern_create_avq,
615+
.destroy_avq = vp_modern_destroy_avq,
548616
};
549617

550618
static const struct virtio_config_ops virtio_pci_config_ops = {
@@ -565,6 +633,8 @@ static const struct virtio_config_ops virtio_pci_config_ops = {
565633
.get_shm_region = vp_get_shm_region,
566634
.disable_vq_and_reset = vp_modern_disable_vq_and_reset,
567635
.enable_vq_after_reset = vp_modern_enable_vq_after_reset,
636+
.create_avq = vp_modern_create_avq,
637+
.destroy_avq = vp_modern_destroy_avq,
568638
};
569639

570640
/* the PCI probing function */
@@ -588,6 +658,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
588658
vp_dev->config_vector = vp_config_vector;
589659
vp_dev->setup_vq = setup_vq;
590660
vp_dev->del_vq = del_vq;
661+
vp_dev->is_avq = vp_is_avq;
591662
vp_dev->isr = mdev->isr;
592663
vp_dev->vdev.id = mdev->id;
593664

drivers/virtio/virtio_pci_modern_dev.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ static inline void check_offsets(void)
207207
offsetof(struct virtio_pci_modern_common_cfg, queue_notify_data));
208208
BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_RESET !=
209209
offsetof(struct virtio_pci_modern_common_cfg, queue_reset));
210+
BUILD_BUG_ON(VIRTIO_PCI_COMMON_ADM_Q_IDX !=
211+
offsetof(struct virtio_pci_modern_common_cfg, admin_queue_index));
212+
BUILD_BUG_ON(VIRTIO_PCI_COMMON_ADM_Q_NUM !=
213+
offsetof(struct virtio_pci_modern_common_cfg, admin_queue_num));
210214
}
211215

212216
/*
@@ -296,7 +300,7 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev)
296300
mdev->common = vp_modern_map_capability(mdev, common,
297301
sizeof(struct virtio_pci_common_cfg), 4, 0,
298302
offsetofend(struct virtio_pci_modern_common_cfg,
299-
queue_reset),
303+
admin_queue_num),
300304
&mdev->common_len, NULL);
301305
if (!mdev->common)
302306
goto err_map_common;
@@ -719,6 +723,24 @@ void __iomem *vp_modern_map_vq_notify(struct virtio_pci_modern_device *mdev,
719723
}
720724
EXPORT_SYMBOL_GPL(vp_modern_map_vq_notify);
721725

726+
u16 vp_modern_avq_num(struct virtio_pci_modern_device *mdev)
727+
{
728+
struct virtio_pci_modern_common_cfg __iomem *cfg;
729+
730+
cfg = (struct virtio_pci_modern_common_cfg __iomem *)mdev->common;
731+
return vp_ioread16(&cfg->admin_queue_num);
732+
}
733+
EXPORT_SYMBOL_GPL(vp_modern_avq_num);
734+
735+
u16 vp_modern_avq_index(struct virtio_pci_modern_device *mdev)
736+
{
737+
struct virtio_pci_modern_common_cfg __iomem *cfg;
738+
739+
cfg = (struct virtio_pci_modern_common_cfg __iomem *)mdev->common;
740+
return vp_ioread16(&cfg->admin_queue_index);
741+
}
742+
EXPORT_SYMBOL_GPL(vp_modern_avq_index);
743+
722744
MODULE_VERSION("0.1");
723745
MODULE_DESCRIPTION("Modern Virtio PCI Device");
724746
MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>");

include/linux/virtio_config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ typedef void vq_callback_t(struct virtqueue *);
9393
* Returns 0 on success or error status
9494
* If disable_vq_and_reset is set, then enable_vq_after_reset must also be
9595
* set.
96+
* @create_avq: create admin virtqueue resource.
97+
* @destroy_avq: destroy admin virtqueue resource.
9698
*/
9799
struct virtio_config_ops {
98100
void (*get)(struct virtio_device *vdev, unsigned offset,
@@ -120,6 +122,8 @@ struct virtio_config_ops {
120122
struct virtio_shm_region *region, u8 id);
121123
int (*disable_vq_and_reset)(struct virtqueue *vq);
122124
int (*enable_vq_after_reset)(struct virtqueue *vq);
125+
int (*create_avq)(struct virtio_device *vdev);
126+
void (*destroy_avq)(struct virtio_device *vdev);
123127
};
124128

125129
/* If driver didn't advertise the feature, it will never appear. */

include/linux/virtio_pci_modern.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,6 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev);
125125
void vp_modern_remove(struct virtio_pci_modern_device *mdev);
126126
int vp_modern_get_queue_reset(struct virtio_pci_modern_device *mdev, u16 index);
127127
void vp_modern_set_queue_reset(struct virtio_pci_modern_device *mdev, u16 index);
128+
u16 vp_modern_avq_num(struct virtio_pci_modern_device *mdev);
129+
u16 vp_modern_avq_index(struct virtio_pci_modern_device *mdev);
128130
#endif

include/uapi/linux/virtio_pci.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ struct virtio_pci_modern_common_cfg {
175175

176176
__le16 queue_notify_data; /* read-write */
177177
__le16 queue_reset; /* read-write */
178+
179+
__le16 admin_queue_index; /* read-only */
180+
__le16 admin_queue_num; /* read-only */
178181
};
179182

180183
/* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
@@ -215,6 +218,8 @@ struct virtio_pci_cfg_cap {
215218
#define VIRTIO_PCI_COMMON_Q_USEDHI 52
216219
#define VIRTIO_PCI_COMMON_Q_NDATA 56
217220
#define VIRTIO_PCI_COMMON_Q_RESET 58
221+
#define VIRTIO_PCI_COMMON_ADM_Q_IDX 60
222+
#define VIRTIO_PCI_COMMON_ADM_Q_NUM 62
218223

219224
#endif /* VIRTIO_PCI_NO_MODERN */
220225

0 commit comments

Comments
 (0)