Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <mst@redhat.com>
Signed-off-by: Yishai Hadas <yishaih@nvidia.com>
Link: https://lore.kernel.org/r/20241113115200.209269-5-yishaih@nvidia.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

authored by

Yishai Hadas and committed by
Alex Williamson
52a22c0e bfcad518

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