Skip to content

Commit 92792ac

Browse files
Feng LiuAlex Williamson
authored andcommitted
virtio-pci: Introduce admin command sending function
Add support for sending admin command through admin virtqueue interface. Abort any inflight admin commands once device reset completes. Activate admin queue when device becomes ready; deactivate on device reset. To comply to the below specification statement [1], the admin virtqueue is activated for upper layer users only after setting DRIVER_OK status. [1] The driver MUST NOT send any buffer available notifications to the device before setting DRIVER_OK. Signed-off-by: Feng Liu <feliu@nvidia.com> Reviewed-by: Parav Pandit <parav@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-4-yishaih@nvidia.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent fd27ef6 commit 92792ac

4 files changed

Lines changed: 177 additions & 2 deletions

File tree

drivers/virtio/virtio_pci_common.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/virtio_pci_modern.h>
3030
#include <linux/highmem.h>
3131
#include <linux/spinlock.h>
32+
#include <linux/mutex.h>
3233

3334
struct virtio_pci_vq_info {
3435
/* the actual virtqueue */
@@ -44,6 +45,8 @@ struct virtio_pci_vq_info {
4445
struct virtio_pci_admin_vq {
4546
/* Virtqueue info associated with this admin queue. */
4647
struct virtio_pci_vq_info info;
48+
/* serializing admin commands execution and virtqueue deletion */
49+
struct mutex cmd_lock;
4750
/* Name of the admin queue: avq.$vq_index. */
4851
char name[10];
4952
u16 vq_index;
@@ -152,4 +155,7 @@ static inline void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev)
152155
int virtio_pci_modern_probe(struct virtio_pci_device *);
153156
void virtio_pci_modern_remove(struct virtio_pci_device *);
154157

158+
int vp_modern_admin_cmd_exec(struct virtio_device *vdev,
159+
struct virtio_admin_cmd *cmd);
160+
155161
#endif

drivers/virtio/virtio_pci_modern.c

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,132 @@ static bool vp_is_avq(struct virtio_device *vdev, unsigned int index)
3838
return index == vp_dev->admin_vq.vq_index;
3939
}
4040

41+
static int virtqueue_exec_admin_cmd(struct virtio_pci_admin_vq *admin_vq,
42+
struct scatterlist **sgs,
43+
unsigned int out_num,
44+
unsigned int in_num,
45+
void *data)
46+
{
47+
struct virtqueue *vq;
48+
int ret, len;
49+
50+
vq = admin_vq->info.vq;
51+
if (!vq)
52+
return -EIO;
53+
54+
ret = virtqueue_add_sgs(vq, sgs, out_num, in_num, data, GFP_KERNEL);
55+
if (ret < 0)
56+
return -EIO;
57+
58+
if (unlikely(!virtqueue_kick(vq)))
59+
return -EIO;
60+
61+
while (!virtqueue_get_buf(vq, &len) &&
62+
!virtqueue_is_broken(vq))
63+
cpu_relax();
64+
65+
if (virtqueue_is_broken(vq))
66+
return -EIO;
67+
68+
return 0;
69+
}
70+
71+
int vp_modern_admin_cmd_exec(struct virtio_device *vdev,
72+
struct virtio_admin_cmd *cmd)
73+
{
74+
struct scatterlist *sgs[VIRTIO_AVQ_SGS_MAX], hdr, stat;
75+
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
76+
struct virtio_admin_cmd_status *va_status;
77+
unsigned int out_num = 0, in_num = 0;
78+
struct virtio_admin_cmd_hdr *va_hdr;
79+
u16 status;
80+
int ret;
81+
82+
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
83+
return -EOPNOTSUPP;
84+
85+
va_status = kzalloc(sizeof(*va_status), GFP_KERNEL);
86+
if (!va_status)
87+
return -ENOMEM;
88+
89+
va_hdr = kzalloc(sizeof(*va_hdr), GFP_KERNEL);
90+
if (!va_hdr) {
91+
ret = -ENOMEM;
92+
goto err_alloc;
93+
}
94+
95+
va_hdr->opcode = cmd->opcode;
96+
va_hdr->group_type = cmd->group_type;
97+
va_hdr->group_member_id = cmd->group_member_id;
98+
99+
/* Add header */
100+
sg_init_one(&hdr, va_hdr, sizeof(*va_hdr));
101+
sgs[out_num] = &hdr;
102+
out_num++;
103+
104+
if (cmd->data_sg) {
105+
sgs[out_num] = cmd->data_sg;
106+
out_num++;
107+
}
108+
109+
/* Add return status */
110+
sg_init_one(&stat, va_status, sizeof(*va_status));
111+
sgs[out_num + in_num] = &stat;
112+
in_num++;
113+
114+
if (cmd->result_sg) {
115+
sgs[out_num + in_num] = cmd->result_sg;
116+
in_num++;
117+
}
118+
119+
mutex_lock(&vp_dev->admin_vq.cmd_lock);
120+
ret = virtqueue_exec_admin_cmd(&vp_dev->admin_vq, sgs,
121+
out_num, in_num, sgs);
122+
mutex_unlock(&vp_dev->admin_vq.cmd_lock);
123+
124+
if (ret) {
125+
dev_err(&vdev->dev,
126+
"Failed to execute command on admin vq: %d\n.", ret);
127+
goto err_cmd_exec;
128+
}
129+
130+
status = le16_to_cpu(va_status->status);
131+
if (status != VIRTIO_ADMIN_STATUS_OK) {
132+
dev_err(&vdev->dev,
133+
"admin command error: status(%#x) qualifier(%#x)\n",
134+
status, le16_to_cpu(va_status->status_qualifier));
135+
ret = -status;
136+
}
137+
138+
err_cmd_exec:
139+
kfree(va_hdr);
140+
err_alloc:
141+
kfree(va_status);
142+
return ret;
143+
}
144+
145+
static void vp_modern_avq_activate(struct virtio_device *vdev)
146+
{
147+
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
148+
struct virtio_pci_admin_vq *admin_vq = &vp_dev->admin_vq;
149+
150+
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
151+
return;
152+
153+
__virtqueue_unbreak(admin_vq->info.vq);
154+
}
155+
156+
static void vp_modern_avq_deactivate(struct virtio_device *vdev)
157+
{
158+
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
159+
struct virtio_pci_admin_vq *admin_vq = &vp_dev->admin_vq;
160+
161+
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
162+
return;
163+
164+
__virtqueue_break(admin_vq->info.vq);
165+
}
166+
41167
static void vp_transport_features(struct virtio_device *vdev, u64 features)
42168
{
43169
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
@@ -213,6 +339,8 @@ static void vp_set_status(struct virtio_device *vdev, u8 status)
213339
/* We should never be setting status to 0. */
214340
BUG_ON(status == 0);
215341
vp_modern_set_status(&vp_dev->mdev, status);
342+
if (status & VIRTIO_CONFIG_S_DRIVER_OK)
343+
vp_modern_avq_activate(vdev);
216344
}
217345

218346
static void vp_reset(struct virtio_device *vdev)
@@ -229,6 +357,9 @@ static void vp_reset(struct virtio_device *vdev)
229357
*/
230358
while (vp_modern_get_status(mdev))
231359
msleep(1);
360+
361+
vp_modern_avq_deactivate(vdev);
362+
232363
/* Flush pending VQ/configuration callbacks. */
233364
vp_synchronize_vectors(vdev);
234365
}
@@ -404,8 +535,11 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
404535
goto err;
405536
}
406537

407-
if (is_avq)
538+
if (is_avq) {
539+
mutex_lock(&vp_dev->admin_vq.cmd_lock);
408540
vp_dev->admin_vq.info.vq = vq;
541+
mutex_unlock(&vp_dev->admin_vq.cmd_lock);
542+
}
409543

410544
return vq;
411545

@@ -442,8 +576,11 @@ static void del_vq(struct virtio_pci_vq_info *info)
442576
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
443577
struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
444578

445-
if (vp_is_avq(&vp_dev->vdev, vq->index))
579+
if (vp_is_avq(&vp_dev->vdev, vq->index)) {
580+
mutex_lock(&vp_dev->admin_vq.cmd_lock);
446581
vp_dev->admin_vq.info.vq = NULL;
582+
mutex_unlock(&vp_dev->admin_vq.cmd_lock);
583+
}
447584

448585
if (vp_dev->msix_enabled)
449586
vp_modern_queue_vector(mdev, vq->index,
@@ -662,12 +799,14 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
662799
vp_dev->isr = mdev->isr;
663800
vp_dev->vdev.id = mdev->id;
664801

802+
mutex_init(&vp_dev->admin_vq.cmd_lock);
665803
return 0;
666804
}
667805

668806
void virtio_pci_modern_remove(struct virtio_pci_device *vp_dev)
669807
{
670808
struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
671809

810+
mutex_destroy(&vp_dev->admin_vq.cmd_lock);
672811
vp_modern_remove(mdev);
673812
}

include/linux/virtio.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ int virtqueue_resize(struct virtqueue *vq, u32 num,
103103
int virtqueue_reset(struct virtqueue *vq,
104104
void (*recycle)(struct virtqueue *vq, void *buf));
105105

106+
struct virtio_admin_cmd {
107+
__le16 opcode;
108+
__le16 group_type;
109+
__le64 group_member_id;
110+
struct scatterlist *data_sg;
111+
struct scatterlist *result_sg;
112+
};
113+
106114
/**
107115
* struct virtio_device - representation of a device using virtio
108116
* @index: unique position on the virtio bus

include/uapi/linux/virtio_pci.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,4 +223,26 @@ struct virtio_pci_cfg_cap {
223223

224224
#endif /* VIRTIO_PCI_NO_MODERN */
225225

226+
/* Admin command status. */
227+
#define VIRTIO_ADMIN_STATUS_OK 0
228+
229+
struct __packed virtio_admin_cmd_hdr {
230+
__le16 opcode;
231+
/*
232+
* 1 - SR-IOV
233+
* 2-65535 - reserved
234+
*/
235+
__le16 group_type;
236+
/* Unused, reserved for future extensions. */
237+
__u8 reserved1[12];
238+
__le64 group_member_id;
239+
};
240+
241+
struct __packed virtio_admin_cmd_status {
242+
__le16 status;
243+
__le16 status_qualifier;
244+
/* Unused, reserved for future extensions. */
245+
__u8 reserved2[4];
246+
};
247+
226248
#endif

0 commit comments

Comments
 (0)