1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved 4 */ 5 6 #include <linux/virtio_pci_admin.h> 7 #include "virtio_pci_common.h" 8 9 /* 10 * virtio_pci_admin_has_legacy_io - Checks whether the legacy IO 11 * commands are supported 12 * @dev: VF pci_dev 13 * 14 * Returns true on success. 15 */ 16 bool virtio_pci_admin_has_legacy_io(struct pci_dev *pdev) 17 { 18 struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev); 19 struct virtio_pci_device *vp_dev; 20 21 if (!virtio_dev) 22 return false; 23 24 if (!virtio_has_feature(virtio_dev, VIRTIO_F_ADMIN_VQ)) 25 return false; 26 27 vp_dev = to_vp_device(virtio_dev); 28 29 if ((vp_dev->admin_vq.supported_cmds & VIRTIO_LEGACY_ADMIN_CMD_BITMAP) == 30 VIRTIO_LEGACY_ADMIN_CMD_BITMAP) 31 return true; 32 return false; 33 } 34 EXPORT_SYMBOL_GPL(virtio_pci_admin_has_legacy_io); 35 36 static int virtio_pci_admin_legacy_io_write(struct pci_dev *pdev, u16 opcode, 37 u8 offset, u8 size, u8 *buf) 38 { 39 struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev); 40 struct virtio_admin_cmd_legacy_wr_data *data; 41 struct virtio_admin_cmd cmd = {}; 42 struct scatterlist data_sg; 43 int vf_id; 44 int ret; 45 46 if (!virtio_dev) 47 return -ENODEV; 48 49 vf_id = pci_iov_vf_id(pdev); 50 if (vf_id < 0) 51 return vf_id; 52 53 data = kzalloc(sizeof(*data) + size, GFP_KERNEL); 54 if (!data) 55 return -ENOMEM; 56 57 data->offset = offset; 58 memcpy(data->registers, buf, size); 59 sg_init_one(&data_sg, data, sizeof(*data) + size); 60 cmd.opcode = cpu_to_le16(opcode); 61 cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV); 62 cmd.group_member_id = cpu_to_le64(vf_id + 1); 63 cmd.data_sg = &data_sg; 64 ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd); 65 66 kfree(data); 67 return ret; 68 } 69 70 /* 71 * virtio_pci_admin_legacy_io_write_common - Write legacy common configuration 72 * of a member device 73 * @dev: VF pci_dev 74 * @offset: starting byte offset within the common configuration area to write to 75 * @size: size of the data to write 76 * @buf: buffer which holds the data 77 * 78 * Note: caller must serialize access for the given device. 79 * Returns 0 on success, or negative on failure. 80 */ 81 int virtio_pci_admin_legacy_common_io_write(struct pci_dev *pdev, u8 offset, 82 u8 size, u8 *buf) 83 { 84 return virtio_pci_admin_legacy_io_write(pdev, 85 VIRTIO_ADMIN_CMD_LEGACY_COMMON_CFG_WRITE, 86 offset, size, buf); 87 } 88 EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_common_io_write); 89 90 /* 91 * virtio_pci_admin_legacy_io_write_device - Write legacy device configuration 92 * of a member device 93 * @dev: VF pci_dev 94 * @offset: starting byte offset within the device configuration area to write to 95 * @size: size of the data to write 96 * @buf: buffer which holds the data 97 * 98 * Note: caller must serialize access for the given device. 99 * Returns 0 on success, or negative on failure. 100 */ 101 int virtio_pci_admin_legacy_device_io_write(struct pci_dev *pdev, u8 offset, 102 u8 size, u8 *buf) 103 { 104 return virtio_pci_admin_legacy_io_write(pdev, 105 VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_WRITE, 106 offset, size, buf); 107 } 108 EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_device_io_write); 109 110 static int virtio_pci_admin_legacy_io_read(struct pci_dev *pdev, u16 opcode, 111 u8 offset, u8 size, u8 *buf) 112 { 113 struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev); 114 struct virtio_admin_cmd_legacy_rd_data *data; 115 struct scatterlist data_sg, result_sg; 116 struct virtio_admin_cmd cmd = {}; 117 int vf_id; 118 int ret; 119 120 if (!virtio_dev) 121 return -ENODEV; 122 123 vf_id = pci_iov_vf_id(pdev); 124 if (vf_id < 0) 125 return vf_id; 126 127 data = kzalloc(sizeof(*data), GFP_KERNEL); 128 if (!data) 129 return -ENOMEM; 130 131 data->offset = offset; 132 sg_init_one(&data_sg, data, sizeof(*data)); 133 sg_init_one(&result_sg, buf, size); 134 cmd.opcode = cpu_to_le16(opcode); 135 cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV); 136 cmd.group_member_id = cpu_to_le64(vf_id + 1); 137 cmd.data_sg = &data_sg; 138 cmd.result_sg = &result_sg; 139 ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd); 140 141 kfree(data); 142 return ret; 143 } 144 145 /* 146 * virtio_pci_admin_legacy_device_io_read - Read legacy device configuration of 147 * a member device 148 * @dev: VF pci_dev 149 * @offset: starting byte offset within the device configuration area to read from 150 * @size: size of the data to be read 151 * @buf: buffer to hold the returned data 152 * 153 * Note: caller must serialize access for the given device. 154 * Returns 0 on success, or negative on failure. 155 */ 156 int virtio_pci_admin_legacy_device_io_read(struct pci_dev *pdev, u8 offset, 157 u8 size, u8 *buf) 158 { 159 return virtio_pci_admin_legacy_io_read(pdev, 160 VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_READ, 161 offset, size, buf); 162 } 163 EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_device_io_read); 164 165 /* 166 * virtio_pci_admin_legacy_common_io_read - Read legacy common configuration of 167 * a member device 168 * @dev: VF pci_dev 169 * @offset: starting byte offset within the common configuration area to read from 170 * @size: size of the data to be read 171 * @buf: buffer to hold the returned data 172 * 173 * Note: caller must serialize access for the given device. 174 * Returns 0 on success, or negative on failure. 175 */ 176 int virtio_pci_admin_legacy_common_io_read(struct pci_dev *pdev, u8 offset, 177 u8 size, u8 *buf) 178 { 179 return virtio_pci_admin_legacy_io_read(pdev, 180 VIRTIO_ADMIN_CMD_LEGACY_COMMON_CFG_READ, 181 offset, size, buf); 182 } 183 EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_common_io_read); 184 185 /* 186 * virtio_pci_admin_legacy_io_notify_info - Read the queue notification 187 * information for legacy interface 188 * @dev: VF pci_dev 189 * @req_bar_flags: requested bar flags 190 * @bar: on output the BAR number of the owner or member device 191 * @bar_offset: on output the offset within bar 192 * 193 * Returns 0 on success, or negative on failure. 194 */ 195 int virtio_pci_admin_legacy_io_notify_info(struct pci_dev *pdev, 196 u8 req_bar_flags, u8 *bar, 197 u64 *bar_offset) 198 { 199 struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev); 200 struct virtio_admin_cmd_notify_info_result *result; 201 struct virtio_admin_cmd cmd = {}; 202 struct scatterlist result_sg; 203 int vf_id; 204 int ret; 205 206 if (!virtio_dev) 207 return -ENODEV; 208 209 vf_id = pci_iov_vf_id(pdev); 210 if (vf_id < 0) 211 return vf_id; 212 213 result = kzalloc(sizeof(*result), GFP_KERNEL); 214 if (!result) 215 return -ENOMEM; 216 217 sg_init_one(&result_sg, result, sizeof(*result)); 218 cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_LEGACY_NOTIFY_INFO); 219 cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV); 220 cmd.group_member_id = cpu_to_le64(vf_id + 1); 221 cmd.result_sg = &result_sg; 222 ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd); 223 if (!ret) { 224 struct virtio_admin_cmd_notify_info_data *entry; 225 int i; 226 227 ret = -ENOENT; 228 for (i = 0; i < VIRTIO_ADMIN_CMD_MAX_NOTIFY_INFO; i++) { 229 entry = &result->entries[i]; 230 if (entry->flags == VIRTIO_ADMIN_CMD_NOTIFY_INFO_FLAGS_END) 231 break; 232 if (entry->flags != req_bar_flags) 233 continue; 234 *bar = entry->bar; 235 *bar_offset = le64_to_cpu(entry->offset); 236 ret = 0; 237 break; 238 } 239 } 240 241 kfree(result); 242 return ret; 243 } 244 EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_io_notify_info); 245