Merge branch 'for-6.9/amd-sfh' into for-linus
[sfrench/cifs-2.6.git] / drivers / virtio / virtio_pci_admin_legacy_io.c
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);