History

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.

Feng Liu committed 2 years ago

Commit 92792ac1 parent fd27ef64 files · +177 −2Browse files

Unified · Split

4 files
  1. drivers/virtio/virtio_pci_common.h +6 −0
  2. drivers/virtio/virtio_pci_modern.c +141 −2
  3. include/linux/virtio.h +8 −0
  4. include/uapi/linux/virtio_pci.h +22 −0
drivers/virtio/virtio_pci_common.h+6−0
@@ -29,6 +29,7 @@ · 28 unmodified lines
29#include <linux/virtio_pci_modern.h>29#include <linux/virtio_pci_modern.h>
30#include <linux/highmem.h>30#include <linux/highmem.h>
31#include <linux/spinlock.h>31#include <linux/spinlock.h>
32#include <linux/mutex.h>
32 33
33struct virtio_pci_vq_info {34struct virtio_pci_vq_info {
34 /* the actual virtqueue */35 /* the actual virtqueue */
@@ -44,6 +45,8 @@ struct virtio_pci_vq_info { · 9 unmodified lines
44struct virtio_pci_admin_vq {45struct virtio_pci_admin_vq {
45 /* Virtqueue info associated with this admin queue. */46 /* Virtqueue info associated with this admin queue. */
46 struct virtio_pci_vq_info info;47 struct virtio_pci_vq_info info;
48 /* serializing admin commands execution and virtqueue deletion */
49 struct mutex cmd_lock;
47 /* Name of the admin queue: avq.$vq_index. */50 /* Name of the admin queue: avq.$vq_index. */
48 char name[10];51 char name[10];
49 u16 vq_index;52 u16 vq_index;
@@ -152,4 +155,7 @@ static inline void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev) · 102 unmodified lines
152int virtio_pci_modern_probe(struct virtio_pci_device *);155int virtio_pci_modern_probe(struct virtio_pci_device *);
153void virtio_pci_modern_remove(struct virtio_pci_device *);156void virtio_pci_modern_remove(struct virtio_pci_device *);
154 157
158int vp_modern_admin_cmd_exec(struct virtio_device *vdev,
159 struct virtio_admin_cmd *cmd);
160
155#endif161#endif
drivers/virtio/virtio_pci_modern.c+141−2
@@ -38,6 +38,132 @@ static bool vp_is_avq(struct virtio_device *vdev, unsigned int index) · 37 unmodified lines
38 return index == vp_dev->admin_vq.vq_index;38 return index == vp_dev->admin_vq.vq_index;
39}39}
40 40
41static 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
71int 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
138err_cmd_exec:
139 kfree(va_hdr);
140err_alloc:
141 kfree(va_status);
142 return ret;
143}
144
145static 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
156static 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
41static void vp_transport_features(struct virtio_device *vdev, u64 features)167static void vp_transport_features(struct virtio_device *vdev, u64 features)
42{168{
43 struct virtio_pci_device *vp_dev = to_vp_device(vdev);169 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) · 169 unmodified lines
213 /* We should never be setting status to 0. */339 /* We should never be setting status to 0. */
214 BUG_ON(status == 0);340 BUG_ON(status == 0);
215 vp_modern_set_status(&vp_dev->mdev, status);341 vp_modern_set_status(&vp_dev->mdev, status);
342 if (status & VIRTIO_CONFIG_S_DRIVER_OK)
343 vp_modern_avq_activate(vdev);
216}344}
217 345
218static void vp_reset(struct virtio_device *vdev)346static void vp_reset(struct virtio_device *vdev)
@@ -229,6 +357,9 @@ static void vp_reset(struct virtio_device *vdev) · 10 unmodified lines
229 */357 */
230 while (vp_modern_get_status(mdev))358 while (vp_modern_get_status(mdev))
231 msleep(1);359 msleep(1);
360
361 vp_modern_avq_deactivate(vdev);
362
232 /* Flush pending VQ/configuration callbacks. */363 /* Flush pending VQ/configuration callbacks. */
233 vp_synchronize_vectors(vdev);364 vp_synchronize_vectors(vdev);
234}365}
@@ -404,8 +535,11 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, · 169 unmodified lines
404 goto err;535 goto err;
405 }536 }
406 537
407 if (is_avq)538 if (is_avq) {
539 mutex_lock(&vp_dev->admin_vq.cmd_lock);
408 vp_dev->admin_vq.info.vq = vq;540 vp_dev->admin_vq.info.vq = vq;
541 mutex_unlock(&vp_dev->admin_vq.cmd_lock);
542 }
409 543
410 return vq;544 return vq;
411 545
@@ -442,8 +576,11 @@ static void del_vq(struct virtio_pci_vq_info *info) · 30 unmodified lines
442 struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);576 struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
443 struct virtio_pci_modern_device *mdev = &vp_dev->mdev;577 struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
444 578
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);
446 vp_dev->admin_vq.info.vq = NULL;581 vp_dev->admin_vq.info.vq = NULL;
582 mutex_unlock(&vp_dev->admin_vq.cmd_lock);
583 }
447 584
448 if (vp_dev->msix_enabled)585 if (vp_dev->msix_enabled)
449 vp_modern_queue_vector(mdev, vq->index,586 vp_modern_queue_vector(mdev, vq->index,
@@ -662,6 +799,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) · 212 unmodified lines
662 vp_dev->isr = mdev->isr;799 vp_dev->isr = mdev->isr;
663 vp_dev->vdev.id = mdev->id;800 vp_dev->vdev.id = mdev->id;
664 801
802 mutex_init(&vp_dev->admin_vq.cmd_lock);
665 return 0;803 return 0;
666}804}
667 805
@@ -669,5 +807,6 @@ void virtio_pci_modern_remove(struct virtio_pci_device *vp_dev) · 1 unmodified line
669{807{
670 struct virtio_pci_modern_device *mdev = &vp_dev->mdev;808 struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
671 809
810 mutex_destroy(&vp_dev->admin_vq.cmd_lock);
672 vp_modern_remove(mdev);811 vp_modern_remove(mdev);
673}812}
include/linux/virtio.h+8−0
@@ -103,6 +103,14 @@ int virtqueue_resize(struct virtqueue *vq, u32 num, · 102 unmodified lines
103int virtqueue_reset(struct virtqueue *vq,103int virtqueue_reset(struct virtqueue *vq,
104 void (*recycle)(struct virtqueue *vq, void *buf));104 void (*recycle)(struct virtqueue *vq, void *buf));
105 105
106struct 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
106/**114/**
107 * struct virtio_device - representation of a device using virtio115 * struct virtio_device - representation of a device using virtio
108 * @index: unique position on the virtio bus116 * @index: unique position on the virtio bus
include/uapi/linux/virtio_pci.h+22−0
@@ -223,4 +223,26 @@ struct virtio_pci_cfg_cap { · 222 unmodified lines
223 223
224#endif /* VIRTIO_PCI_NO_MODERN */224#endif /* VIRTIO_PCI_NO_MODERN */
225 225
226/* Admin command status. */
227#define VIRTIO_ADMIN_STATUS_OK 0
228
229struct __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
241struct __packed virtio_admin_cmd_status {
242 __le16 status;
243 __le16 status_qualifier;
244 /* Unused, reserved for future extensions. */
245 __u8 reserved2[4];
246};
247
226#endif248#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t