Skip to content

Commit 52a22c0

Browse files
yishaihawilliam
authored andcommitted
virtio-pci: Introduce APIs to execute device parts admin commands
Introduce APIs to handle the execution of device parts admin commands. These APIs cover functionalities such as mode setting, object creation and destruction, and operations like parts get/set and metadata retrieval. These APIs will be utilized in upcoming patches within this series. 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 bfcad51 commit 52a22c0

File tree

3 files changed

+366
-1
lines changed

3 files changed

+366
-1
lines changed

drivers/virtio/virtio_pci_common.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,13 @@ struct virtio_device *virtio_pci_vf_get_pf_dev(struct pci_dev *pdev);
173173
#define VIRTIO_DEV_PARTS_ADMIN_CMD_BITMAP \
174174
(BIT_ULL(VIRTIO_ADMIN_CMD_CAP_ID_LIST_QUERY) | \
175175
BIT_ULL(VIRTIO_ADMIN_CMD_DRIVER_CAP_SET) | \
176-
BIT_ULL(VIRTIO_ADMIN_CMD_DEVICE_CAP_GET))
176+
BIT_ULL(VIRTIO_ADMIN_CMD_DEVICE_CAP_GET) | \
177+
BIT_ULL(VIRTIO_ADMIN_CMD_RESOURCE_OBJ_CREATE) | \
178+
BIT_ULL(VIRTIO_ADMIN_CMD_RESOURCE_OBJ_DESTROY) | \
179+
BIT_ULL(VIRTIO_ADMIN_CMD_DEV_PARTS_METADATA_GET) | \
180+
BIT_ULL(VIRTIO_ADMIN_CMD_DEV_PARTS_GET) | \
181+
BIT_ULL(VIRTIO_ADMIN_CMD_DEV_PARTS_SET) | \
182+
BIT_ULL(VIRTIO_ADMIN_CMD_DEV_MODE_SET))
177183

178184
/* Unlike modern drivers which support hardware virtio devices, legacy drivers
179185
* assume software-based devices: e.g. they don't use proper memory barriers

drivers/virtio/virtio_pci_modern.c

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
#include <linux/delay.h>
18+
#include <linux/virtio_pci_admin.h>
1819
#define VIRTIO_PCI_NO_LEGACY
1920
#define VIRTIO_RING_NO_LEGACY
2021
#include "virtio_pci_common.h"
@@ -875,6 +876,353 @@ static bool vp_get_shm_region(struct virtio_device *vdev,
875876
return true;
876877
}
877878

879+
/*
880+
* virtio_pci_admin_has_dev_parts - Checks whether the device parts
881+
* functionality is supported
882+
* @pdev: VF pci_dev
883+
*
884+
* Returns true on success.
885+
*/
886+
bool virtio_pci_admin_has_dev_parts(struct pci_dev *pdev)
887+
{
888+
struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
889+
struct virtio_pci_device *vp_dev;
890+
891+
if (!virtio_dev)
892+
return false;
893+
894+
if (!virtio_has_feature(virtio_dev, VIRTIO_F_ADMIN_VQ))
895+
return false;
896+
897+
vp_dev = to_vp_device(virtio_dev);
898+
899+
if (!((vp_dev->admin_vq.supported_cmds & VIRTIO_DEV_PARTS_ADMIN_CMD_BITMAP) ==
900+
VIRTIO_DEV_PARTS_ADMIN_CMD_BITMAP))
901+
return false;
902+
903+
return vp_dev->admin_vq.max_dev_parts_objects;
904+
}
905+
EXPORT_SYMBOL_GPL(virtio_pci_admin_has_dev_parts);
906+
907+
/*
908+
* virtio_pci_admin_mode_set - Sets the mode of a member device
909+
* @pdev: VF pci_dev
910+
* @flags: device mode's flags
911+
*
912+
* Note: caller must serialize access for the given device.
913+
* Returns 0 on success, or negative on failure.
914+
*/
915+
int virtio_pci_admin_mode_set(struct pci_dev *pdev, u8 flags)
916+
{
917+
struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
918+
struct virtio_admin_cmd_dev_mode_set_data *data;
919+
struct virtio_admin_cmd cmd = {};
920+
struct scatterlist data_sg;
921+
int vf_id;
922+
int ret;
923+
924+
if (!virtio_dev)
925+
return -ENODEV;
926+
927+
vf_id = pci_iov_vf_id(pdev);
928+
if (vf_id < 0)
929+
return vf_id;
930+
931+
data = kzalloc(sizeof(*data), GFP_KERNEL);
932+
if (!data)
933+
return -ENOMEM;
934+
935+
data->flags = flags;
936+
sg_init_one(&data_sg, data, sizeof(*data));
937+
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_DEV_MODE_SET);
938+
cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
939+
cmd.group_member_id = cpu_to_le64(vf_id + 1);
940+
cmd.data_sg = &data_sg;
941+
ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
942+
943+
kfree(data);
944+
return ret;
945+
}
946+
EXPORT_SYMBOL_GPL(virtio_pci_admin_mode_set);
947+
948+
/*
949+
* virtio_pci_admin_obj_create - Creates an object for a given type and operation,
950+
* following the max objects that can be created for that request.
951+
* @pdev: VF pci_dev
952+
* @obj_type: Object type
953+
* @operation_type: Operation type
954+
* @obj_id: Output unique object id
955+
*
956+
* Note: caller must serialize access for the given device.
957+
* Returns 0 on success, or negative on failure.
958+
*/
959+
int virtio_pci_admin_obj_create(struct pci_dev *pdev, u16 obj_type, u8 operation_type,
960+
u32 *obj_id)
961+
{
962+
struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
963+
u16 data_size = sizeof(struct virtio_admin_cmd_resource_obj_create_data);
964+
struct virtio_admin_cmd_resource_obj_create_data *obj_create_data;
965+
struct virtio_resource_obj_dev_parts obj_dev_parts = {};
966+
struct virtio_pci_admin_vq *avq;
967+
struct virtio_admin_cmd cmd = {};
968+
struct scatterlist data_sg;
969+
void *data;
970+
int id = -1;
971+
int vf_id;
972+
int ret;
973+
974+
if (!virtio_dev)
975+
return -ENODEV;
976+
977+
vf_id = pci_iov_vf_id(pdev);
978+
if (vf_id < 0)
979+
return vf_id;
980+
981+
if (obj_type != VIRTIO_RESOURCE_OBJ_DEV_PARTS)
982+
return -EOPNOTSUPP;
983+
984+
if (operation_type != VIRTIO_RESOURCE_OBJ_DEV_PARTS_TYPE_GET &&
985+
operation_type != VIRTIO_RESOURCE_OBJ_DEV_PARTS_TYPE_SET)
986+
return -EINVAL;
987+
988+
avq = &to_vp_device(virtio_dev)->admin_vq;
989+
if (!avq->max_dev_parts_objects)
990+
return -EOPNOTSUPP;
991+
992+
id = ida_alloc_range(&avq->dev_parts_ida, 0,
993+
avq->max_dev_parts_objects - 1, GFP_KERNEL);
994+
if (id < 0)
995+
return id;
996+
997+
*obj_id = id;
998+
data_size += sizeof(obj_dev_parts);
999+
data = kzalloc(data_size, GFP_KERNEL);
1000+
if (!data) {
1001+
ret = -ENOMEM;
1002+
goto end;
1003+
}
1004+
1005+
obj_create_data = data;
1006+
obj_create_data->hdr.type = cpu_to_le16(obj_type);
1007+
obj_create_data->hdr.id = cpu_to_le32(*obj_id);
1008+
obj_dev_parts.type = operation_type;
1009+
memcpy(obj_create_data->resource_obj_specific_data, &obj_dev_parts,
1010+
sizeof(obj_dev_parts));
1011+
sg_init_one(&data_sg, data, data_size);
1012+
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_RESOURCE_OBJ_CREATE);
1013+
cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
1014+
cmd.group_member_id = cpu_to_le64(vf_id + 1);
1015+
cmd.data_sg = &data_sg;
1016+
ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
1017+
1018+
kfree(data);
1019+
end:
1020+
if (ret)
1021+
ida_free(&avq->dev_parts_ida, id);
1022+
1023+
return ret;
1024+
}
1025+
EXPORT_SYMBOL_GPL(virtio_pci_admin_obj_create);
1026+
1027+
/*
1028+
* virtio_pci_admin_obj_destroy - Destroys an object of a given type and id
1029+
* @pdev: VF pci_dev
1030+
* @obj_type: Object type
1031+
* @id: Object id
1032+
*
1033+
* Note: caller must serialize access for the given device.
1034+
* Returns 0 on success, or negative on failure.
1035+
*/
1036+
int virtio_pci_admin_obj_destroy(struct pci_dev *pdev, u16 obj_type, u32 id)
1037+
{
1038+
struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
1039+
struct virtio_admin_cmd_resource_obj_cmd_hdr *data;
1040+
struct virtio_pci_device *vp_dev;
1041+
struct virtio_admin_cmd cmd = {};
1042+
struct scatterlist data_sg;
1043+
int vf_id;
1044+
int ret;
1045+
1046+
if (!virtio_dev)
1047+
return -ENODEV;
1048+
1049+
vf_id = pci_iov_vf_id(pdev);
1050+
if (vf_id < 0)
1051+
return vf_id;
1052+
1053+
if (obj_type != VIRTIO_RESOURCE_OBJ_DEV_PARTS)
1054+
return -EINVAL;
1055+
1056+
data = kzalloc(sizeof(*data), GFP_KERNEL);
1057+
if (!data)
1058+
return -ENOMEM;
1059+
1060+
data->type = cpu_to_le16(obj_type);
1061+
data->id = cpu_to_le32(id);
1062+
sg_init_one(&data_sg, data, sizeof(*data));
1063+
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_RESOURCE_OBJ_DESTROY);
1064+
cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
1065+
cmd.group_member_id = cpu_to_le64(vf_id + 1);
1066+
cmd.data_sg = &data_sg;
1067+
ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
1068+
if (!ret) {
1069+
vp_dev = to_vp_device(virtio_dev);
1070+
ida_free(&vp_dev->admin_vq.dev_parts_ida, id);
1071+
}
1072+
1073+
kfree(data);
1074+
return ret;
1075+
}
1076+
EXPORT_SYMBOL_GPL(virtio_pci_admin_obj_destroy);
1077+
1078+
/*
1079+
* virtio_pci_admin_dev_parts_metadata_get - Gets the metadata of the device parts
1080+
* identified by the below attributes.
1081+
* @pdev: VF pci_dev
1082+
* @obj_type: Object type
1083+
* @id: Object id
1084+
* @metadata_type: Metadata type
1085+
* @out: Upon success holds the output for 'metadata type size'
1086+
*
1087+
* Note: caller must serialize access for the given device.
1088+
* Returns 0 on success, or negative on failure.
1089+
*/
1090+
int virtio_pci_admin_dev_parts_metadata_get(struct pci_dev *pdev, u16 obj_type,
1091+
u32 id, u8 metadata_type, u32 *out)
1092+
{
1093+
struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
1094+
struct virtio_admin_cmd_dev_parts_metadata_result *result;
1095+
struct virtio_admin_cmd_dev_parts_metadata_data *data;
1096+
struct scatterlist data_sg, result_sg;
1097+
struct virtio_admin_cmd cmd = {};
1098+
int vf_id;
1099+
int ret;
1100+
1101+
if (!virtio_dev)
1102+
return -ENODEV;
1103+
1104+
if (metadata_type != VIRTIO_ADMIN_CMD_DEV_PARTS_METADATA_TYPE_SIZE)
1105+
return -EOPNOTSUPP;
1106+
1107+
vf_id = pci_iov_vf_id(pdev);
1108+
if (vf_id < 0)
1109+
return vf_id;
1110+
1111+
data = kzalloc(sizeof(*data), GFP_KERNEL);
1112+
if (!data)
1113+
return -ENOMEM;
1114+
1115+
result = kzalloc(sizeof(*result), GFP_KERNEL);
1116+
if (!result) {
1117+
ret = -ENOMEM;
1118+
goto end;
1119+
}
1120+
1121+
data->hdr.type = cpu_to_le16(obj_type);
1122+
data->hdr.id = cpu_to_le32(id);
1123+
data->type = metadata_type;
1124+
sg_init_one(&data_sg, data, sizeof(*data));
1125+
sg_init_one(&result_sg, result, sizeof(*result));
1126+
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_DEV_PARTS_METADATA_GET);
1127+
cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
1128+
cmd.group_member_id = cpu_to_le64(vf_id + 1);
1129+
cmd.data_sg = &data_sg;
1130+
cmd.result_sg = &result_sg;
1131+
ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
1132+
if (!ret)
1133+
*out = le32_to_cpu(result->parts_size.size);
1134+
1135+
kfree(result);
1136+
end:
1137+
kfree(data);
1138+
return ret;
1139+
}
1140+
EXPORT_SYMBOL_GPL(virtio_pci_admin_dev_parts_metadata_get);
1141+
1142+
/*
1143+
* virtio_pci_admin_dev_parts_get - Gets the device parts identified by the below attributes.
1144+
* @pdev: VF pci_dev
1145+
* @obj_type: Object type
1146+
* @id: Object id
1147+
* @get_type: Get type
1148+
* @res_sg: Upon success holds the output result data
1149+
* @res_size: Upon success holds the output result size
1150+
*
1151+
* Note: caller must serialize access for the given device.
1152+
* Returns 0 on success, or negative on failure.
1153+
*/
1154+
int virtio_pci_admin_dev_parts_get(struct pci_dev *pdev, u16 obj_type, u32 id,
1155+
u8 get_type, struct scatterlist *res_sg,
1156+
u32 *res_size)
1157+
{
1158+
struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
1159+
struct virtio_admin_cmd_dev_parts_get_data *data;
1160+
struct scatterlist data_sg;
1161+
struct virtio_admin_cmd cmd = {};
1162+
int vf_id;
1163+
int ret;
1164+
1165+
if (!virtio_dev)
1166+
return -ENODEV;
1167+
1168+
if (get_type != VIRTIO_ADMIN_CMD_DEV_PARTS_GET_TYPE_ALL)
1169+
return -EOPNOTSUPP;
1170+
1171+
vf_id = pci_iov_vf_id(pdev);
1172+
if (vf_id < 0)
1173+
return vf_id;
1174+
1175+
data = kzalloc(sizeof(*data), GFP_KERNEL);
1176+
if (!data)
1177+
return -ENOMEM;
1178+
1179+
data->hdr.type = cpu_to_le16(obj_type);
1180+
data->hdr.id = cpu_to_le32(id);
1181+
data->type = get_type;
1182+
sg_init_one(&data_sg, data, sizeof(*data));
1183+
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_DEV_PARTS_GET);
1184+
cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
1185+
cmd.group_member_id = cpu_to_le64(vf_id + 1);
1186+
cmd.data_sg = &data_sg;
1187+
cmd.result_sg = res_sg;
1188+
ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
1189+
if (!ret)
1190+
*res_size = cmd.result_sg_size;
1191+
1192+
kfree(data);
1193+
return ret;
1194+
}
1195+
EXPORT_SYMBOL_GPL(virtio_pci_admin_dev_parts_get);
1196+
1197+
/*
1198+
* virtio_pci_admin_dev_parts_set - Sets the device parts identified by the below attributes.
1199+
* @pdev: VF pci_dev
1200+
* @data_sg: The device parts data, its layout follows struct virtio_admin_cmd_dev_parts_set_data
1201+
*
1202+
* Note: caller must serialize access for the given device.
1203+
* Returns 0 on success, or negative on failure.
1204+
*/
1205+
int virtio_pci_admin_dev_parts_set(struct pci_dev *pdev, struct scatterlist *data_sg)
1206+
{
1207+
struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
1208+
struct virtio_admin_cmd cmd = {};
1209+
int vf_id;
1210+
1211+
if (!virtio_dev)
1212+
return -ENODEV;
1213+
1214+
vf_id = pci_iov_vf_id(pdev);
1215+
if (vf_id < 0)
1216+
return vf_id;
1217+
1218+
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_DEV_PARTS_SET);
1219+
cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
1220+
cmd.group_member_id = cpu_to_le64(vf_id + 1);
1221+
cmd.data_sg = data_sg;
1222+
return vp_modern_admin_cmd_exec(virtio_dev, &cmd);
1223+
}
1224+
EXPORT_SYMBOL_GPL(virtio_pci_admin_dev_parts_set);
1225+
8781226
static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
8791227
.get = NULL,
8801228
.set = NULL,

include/linux/virtio_pci_admin.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,15 @@ int virtio_pci_admin_legacy_io_notify_info(struct pci_dev *pdev,
2020
u64 *bar_offset);
2121
#endif
2222

23+
bool virtio_pci_admin_has_dev_parts(struct pci_dev *pdev);
24+
int virtio_pci_admin_mode_set(struct pci_dev *pdev, u8 mode);
25+
int virtio_pci_admin_obj_create(struct pci_dev *pdev, u16 obj_type, u8 operation_type,
26+
u32 *obj_id);
27+
int virtio_pci_admin_obj_destroy(struct pci_dev *pdev, u16 obj_type, u32 id);
28+
int virtio_pci_admin_dev_parts_metadata_get(struct pci_dev *pdev, u16 obj_type,
29+
u32 id, u8 metadata_type, u32 *out);
30+
int virtio_pci_admin_dev_parts_get(struct pci_dev *pdev, u16 obj_type, u32 id,
31+
u8 get_type, struct scatterlist *res_sg, u32 *res_size);
32+
int virtio_pci_admin_dev_parts_set(struct pci_dev *pdev, struct scatterlist *data_sg);
33+
2334
#endif /* _LINUX_VIRTIO_PCI_ADMIN_H */

0 commit comments

Comments
 (0)