Skip to content

Commit bfcad51

Browse files
yishaihawilliam
authored andcommitted
virtio: Manage device and driver capabilities via the admin commands
Manage device and driver capabilities via the admin commands. The device exposes its supported features and resource object limits via an administrative command called VIRTIO_ADMIN_CMD_CAP_ID_LIST_QUERY, using the 'self group type.' Each capability is identified by a unique ID, and the driver communicates the functionality and resource limits it plans to utilize. The capability VIRTIO_DEV_PARTS_CAP specifically represents the device's parts resource object limit. Manage the device's parts resource object ID using a common IDA for both get and set operations. Acked-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Yishai Hadas <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alex Williamson <[email protected]>
1 parent 704806c commit bfcad51

File tree

2 files changed

+116
-2
lines changed

2 files changed

+116
-2
lines changed

drivers/virtio/virtio_pci_common.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ struct virtio_pci_admin_vq {
4848
/* Protects virtqueue access. */
4949
spinlock_t lock;
5050
u64 supported_cmds;
51+
u64 supported_caps;
52+
u8 max_dev_parts_objects;
53+
struct ida dev_parts_ida;
5154
/* Name of the admin queue: avq.$vq_index. */
5255
char name[10];
5356
u16 vq_index;
@@ -167,15 +170,21 @@ struct virtio_device *virtio_pci_vf_get_pf_dev(struct pci_dev *pdev);
167170
BIT_ULL(VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_READ) | \
168171
BIT_ULL(VIRTIO_ADMIN_CMD_LEGACY_NOTIFY_INFO))
169172

173+
#define VIRTIO_DEV_PARTS_ADMIN_CMD_BITMAP \
174+
(BIT_ULL(VIRTIO_ADMIN_CMD_CAP_ID_LIST_QUERY) | \
175+
BIT_ULL(VIRTIO_ADMIN_CMD_DRIVER_CAP_SET) | \
176+
BIT_ULL(VIRTIO_ADMIN_CMD_DEVICE_CAP_GET))
177+
170178
/* Unlike modern drivers which support hardware virtio devices, legacy drivers
171179
* assume software-based devices: e.g. they don't use proper memory barriers
172180
* on ARM, use big endian on PPC, etc. X86 drivers are mostly ok though, more
173181
* or less by chance. For now, only support legacy IO on X86.
174182
*/
175183
#ifdef CONFIG_VIRTIO_PCI_ADMIN_LEGACY
176-
#define VIRTIO_ADMIN_CMD_BITMAP VIRTIO_LEGACY_ADMIN_CMD_BITMAP
184+
#define VIRTIO_ADMIN_CMD_BITMAP (VIRTIO_LEGACY_ADMIN_CMD_BITMAP | \
185+
VIRTIO_DEV_PARTS_ADMIN_CMD_BITMAP)
177186
#else
178-
#define VIRTIO_ADMIN_CMD_BITMAP 0
187+
#define VIRTIO_ADMIN_CMD_BITMAP VIRTIO_DEV_PARTS_ADMIN_CMD_BITMAP
179188
#endif
180189

181190
void vp_modern_avq_done(struct virtqueue *vq);

drivers/virtio/virtio_pci_modern.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,117 @@ static void virtio_pci_admin_cmd_list_init(struct virtio_device *virtio_dev)
230230
kfree(data);
231231
}
232232

233+
static void
234+
virtio_pci_admin_cmd_dev_parts_objects_enable(struct virtio_device *virtio_dev)
235+
{
236+
struct virtio_pci_device *vp_dev = to_vp_device(virtio_dev);
237+
struct virtio_admin_cmd_cap_get_data *get_data;
238+
struct virtio_admin_cmd_cap_set_data *set_data;
239+
struct virtio_dev_parts_cap *result;
240+
struct virtio_admin_cmd cmd = {};
241+
struct scatterlist result_sg;
242+
struct scatterlist data_sg;
243+
u8 resource_objects_limit;
244+
u16 set_data_size;
245+
int ret;
246+
247+
get_data = kzalloc(sizeof(*get_data), GFP_KERNEL);
248+
if (!get_data)
249+
return;
250+
251+
result = kzalloc(sizeof(*result), GFP_KERNEL);
252+
if (!result)
253+
goto end;
254+
255+
get_data->id = cpu_to_le16(VIRTIO_DEV_PARTS_CAP);
256+
sg_init_one(&data_sg, get_data, sizeof(*get_data));
257+
sg_init_one(&result_sg, result, sizeof(*result));
258+
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_DEVICE_CAP_GET);
259+
cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
260+
cmd.data_sg = &data_sg;
261+
cmd.result_sg = &result_sg;
262+
ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
263+
if (ret)
264+
goto err_get;
265+
266+
set_data_size = sizeof(*set_data) + sizeof(*result);
267+
set_data = kzalloc(set_data_size, GFP_KERNEL);
268+
if (!set_data)
269+
goto err_get;
270+
271+
set_data->id = cpu_to_le16(VIRTIO_DEV_PARTS_CAP);
272+
273+
/* Set the limit to the minimum value between the GET and SET values
274+
* supported by the device. Since the obj_id for VIRTIO_DEV_PARTS_CAP
275+
* is a globally unique value per PF, there is no possibility of
276+
* overlap between GET and SET operations.
277+
*/
278+
resource_objects_limit = min(result->get_parts_resource_objects_limit,
279+
result->set_parts_resource_objects_limit);
280+
result->get_parts_resource_objects_limit = resource_objects_limit;
281+
result->set_parts_resource_objects_limit = resource_objects_limit;
282+
memcpy(set_data->cap_specific_data, result, sizeof(*result));
283+
sg_init_one(&data_sg, set_data, set_data_size);
284+
cmd.data_sg = &data_sg;
285+
cmd.result_sg = NULL;
286+
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_DRIVER_CAP_SET);
287+
ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
288+
if (ret)
289+
goto err_set;
290+
291+
/* Allocate IDR to manage the dev caps objects */
292+
ida_init(&vp_dev->admin_vq.dev_parts_ida);
293+
vp_dev->admin_vq.max_dev_parts_objects = resource_objects_limit;
294+
295+
err_set:
296+
kfree(set_data);
297+
err_get:
298+
kfree(result);
299+
end:
300+
kfree(get_data);
301+
}
302+
303+
static void virtio_pci_admin_cmd_cap_init(struct virtio_device *virtio_dev)
304+
{
305+
struct virtio_pci_device *vp_dev = to_vp_device(virtio_dev);
306+
struct virtio_admin_cmd_query_cap_id_result *data;
307+
struct virtio_admin_cmd cmd = {};
308+
struct scatterlist result_sg;
309+
int ret;
310+
311+
data = kzalloc(sizeof(*data), GFP_KERNEL);
312+
if (!data)
313+
return;
314+
315+
sg_init_one(&result_sg, data, sizeof(*data));
316+
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_CAP_ID_LIST_QUERY);
317+
cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
318+
cmd.result_sg = &result_sg;
319+
320+
ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
321+
if (ret)
322+
goto end;
323+
324+
/* Max number of caps fits into a single u64 */
325+
BUILD_BUG_ON(sizeof(data->supported_caps) > sizeof(u64));
326+
327+
vp_dev->admin_vq.supported_caps = le64_to_cpu(data->supported_caps[0]);
328+
329+
if (!(vp_dev->admin_vq.supported_caps & (1 << VIRTIO_DEV_PARTS_CAP)))
330+
goto end;
331+
332+
virtio_pci_admin_cmd_dev_parts_objects_enable(virtio_dev);
333+
end:
334+
kfree(data);
335+
}
336+
233337
static void vp_modern_avq_activate(struct virtio_device *vdev)
234338
{
235339
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
236340
return;
237341

238342
virtio_pci_admin_cmd_list_init(vdev);
343+
virtio_pci_admin_cmd_cap_init(vdev);
239344
}
240345

241346
static void vp_modern_avq_cleanup(struct virtio_device *vdev)

0 commit comments

Comments
 (0)