master
c 460 lines 11.8 KB
Raw
1 /*
2 * Functionality for virtio-pci
3 *
4 * Copyright 2025 IBM Corp.
5 * Author(s): Jared Rossi <jrossi@linux.ibm.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "clp.h"
11 #include "pci.h"
12 #include "helper.h"
13 #include "virtio.h"
14 #include "bswap.h"
15 #include "virtio-pci.h"
16 #include "s390-time.h"
17 #include <stdio.h>
18
19 /* Variable offsets used for reads/writes to modern memory regions */
20 VirtioPciCap c_cap; /* Common capabilities */
21 VirtioPciCap d_cap; /* Device capabilities */
22 VirtioPciCap n_cap; /* Notify capabilities */
23 uint32_t notify_mult;
24
25 static int virtio_pci_set_status(uint8_t status)
26 {
27 int rc = vpci_write_byte(c_cap.off + VPCI_C_OFFSET_STATUS, c_cap.bar, status);
28 if (rc) {
29 puts("Failed to write virtio-pci status");
30 return -EIO;
31 }
32
33 return 0;
34 }
35
36 static int virtio_pci_get_status(uint8_t *status)
37 {
38 int rc = vpci_read_byte(c_cap.off + VPCI_C_OFFSET_STATUS, c_cap.bar, status);
39 if (rc) {
40 puts("Failed to read virtio-pci status");
41 return -EIO;
42 }
43
44 return 0;
45 }
46
47 /* virtio spec v1.3 section 4.1.2.1 */
48 void virtio_pci_id2type(VDev *vdev, uint16_t device_id)
49 {
50 switch (device_id) {
51 case 0x1042:
52 case 0x1001:
53 vdev->dev_type = VIRTIO_ID_BLOCK;
54 break;
55 default:
56 vdev->dev_type = 0;
57 }
58 }
59
60 int virtio_pci_reset(VDev *vdev)
61 {
62 int rc;
63 uint8_t status = 0;
64
65 rc = virtio_pci_set_status(status);
66 rc |= virtio_pci_get_status(&status);
67
68 if (rc || status) {
69 puts("Failed to reset virtio-pci device");
70 return 1;
71 }
72
73 return 0;
74 }
75
76 long virtio_pci_notify(VRing *vr)
77 {
78 uint32_t offset = n_cap.off + notify_mult * vr->pci_notify;
79 return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vr->id);
80 }
81
82 /*
83 * Wrappers to byte swap common data sizes then write
84 */
85 int vpci_write_byte(uint64_t offset, uint8_t pcias, uint8_t data)
86 {
87 return pci_write(virtio_get_device()->pci_fh, offset, pcias, (uint64_t) data, 1);
88 }
89
90 int vpci_bswap16_write(uint64_t offset, uint8_t pcias, uint16_t data)
91 {
92 uint64_t le_data = bswap16(data);
93 return pci_write(virtio_get_device()->pci_fh, offset, pcias, le_data, 2);
94 }
95
96 int vpci_bswap32_write(uint64_t offset, uint8_t pcias, uint32_t data)
97 {
98 uint64_t le_data = bswap32(data);
99 return pci_write(virtio_get_device()->pci_fh, offset, pcias, le_data, 4);
100 }
101
102 int vpci_bswap64_write(uint64_t offset, uint8_t pcias, uint64_t data)
103 {
104 uint64_t le_data = bswap64(data);
105 return pci_write(virtio_get_device()->pci_fh, offset, pcias, le_data, 8);
106 }
107
108 /*
109 * Wrappers to read common data sizes then byte swap
110 */
111 int vpci_read_byte(uint64_t offset, uint8_t pcias, uint8_t *buf)
112 {
113 return pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, 1);
114 }
115
116 int vpci_read_bswap16(uint64_t offset, uint8_t pcias, uint16_t *buf)
117 {
118 int rc = pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, 2);
119 *buf = bswap16(*buf);
120 return rc;
121 }
122
123 int vpci_read_bswap32(uint64_t offset, uint8_t pcias, uint32_t *buf)
124 {
125 int rc = pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, 4);
126 *buf = bswap32(*buf);
127 return rc;
128 }
129
130 int vpci_read_bswap64(uint64_t offset, uint8_t pcias, uint64_t *buf)
131 {
132 int rc = pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, 8);
133 *buf = bswap64(*buf);
134 return rc;
135 }
136
137 /*
138 * Read to an arbitrary length buffer without byte swapping
139 */
140 int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len)
141 {
142 uint8_t readlen;
143 int rc;
144 int remaining = len;
145
146 /* Read bytes in powers of 2, up to a maximum of 8 bytes per read */
147 while (remaining) {
148 for (int i = 3; i >= 0; i--) {
149 readlen = 1 << i;
150 if (remaining >= readlen) {
151 break;
152 }
153 }
154
155 rc = pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, readlen);
156 if (rc) {
157 return -1;
158 }
159
160 remaining -= readlen;
161 buf += readlen;
162 offset += readlen;
163 }
164
165 return 0;
166 }
167
168 static int vpci_set_selected_vq(uint16_t queue_num)
169 {
170 return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_SELECT, c_cap.bar, queue_num);
171 }
172
173 static int vpci_set_queue_enable(uint16_t enabled)
174 {
175 return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_ENABLE, c_cap.bar, enabled);
176 }
177
178 static int set_pci_vq_addr(uint64_t config_off, void *addr)
179 {
180 return vpci_bswap64_write(c_cap.off + config_off, c_cap.bar, (uint64_t) addr);
181 }
182
183 static int virtio_pci_get_blk_config(void)
184 {
185 VirtioBlkConfig *cfg = &virtio_get_device()->config.blk;
186 int rc = vpci_read_flex(d_cap.off, d_cap.bar, cfg, sizeof(VirtioBlkConfig));
187
188 /* single byte fields are not touched */
189 cfg->capacity = bswap64(cfg->capacity);
190 cfg->size_max = bswap32(cfg->size_max);
191 cfg->seg_max = bswap32(cfg->seg_max);
192
193 cfg->geometry.cylinders = bswap16(cfg->geometry.cylinders);
194
195 cfg->blk_size = bswap32(cfg->blk_size);
196 cfg->min_io_size = bswap16(cfg->min_io_size);
197 cfg->opt_io_size = bswap32(cfg->opt_io_size);
198
199 return rc;
200 }
201
202 static int virtio_pci_negotiate(void)
203 {
204 int i, rc;
205 VDev *vdev = virtio_get_device();
206 struct VirtioFeatureDesc {
207 uint32_t features;
208 uint8_t index;
209 } __attribute__((packed)) feats;
210
211 for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
212 feats.features = 0;
213 feats.index = i;
214
215 rc = vpci_bswap32_write(c_cap.off + VPCI_C_OFFSET_DFSELECT, c_cap.bar,
216 feats.index);
217 rc |= vpci_read_flex(c_cap.off + VPCI_C_OFFSET_DF, c_cap.bar, &feats, 4);
218
219 vdev->guest_features[i] &= bswap32(feats.features);
220 feats.features = vdev->guest_features[i];
221
222
223 rc |= vpci_bswap32_write(c_cap.off + VPCI_C_OFFSET_GFSELECT, c_cap.bar,
224 feats.index);
225 rc |= vpci_bswap32_write(c_cap.off + VPCI_C_OFFSET_GF, c_cap.bar,
226 feats.features);
227 }
228
229 return rc;
230 }
231
232 /*
233 * Find the position of the capability config within PCI configuration
234 * space for a given cfg type. Return the position if found, otherwise 0.
235 */
236 static uint8_t virtio_pci_find_cap_pos(uint8_t cfg_type)
237 {
238 uint8_t next, cfg;
239 int rc;
240
241 rc = vpci_read_byte(PCI_CAPABILITY_LIST, PCI_CFGBAR, &next);
242 rc |= vpci_read_byte(next + 3, PCI_CFGBAR, &cfg);
243
244 while (!rc && (cfg != cfg_type) && next) {
245 rc = vpci_read_byte(next + 1, PCI_CFGBAR, &next);
246 rc |= vpci_read_byte(next + 3, PCI_CFGBAR, &cfg);
247 }
248
249 return rc ? 0 : next;
250 }
251
252 /*
253 * Read PCI configuration space to find the offset of the Common, Device, and
254 * Notification memory regions within the modern memory space.
255 * Returns 0 if success, 1 if a capability could not be located, or a
256 * negative RC if the configuration read failed.
257 */
258 static int virtio_pci_read_pci_cap_config(void)
259 {
260 uint8_t pos;
261 int rc;
262
263 /* Common capabilities */
264 pos = virtio_pci_find_cap_pos(VPCI_CAP_COMMON_CFG);
265 if (!pos) {
266 puts("Failed to locate PCI common configuration");
267 return 1;
268 }
269
270 rc = vpci_read_byte(pos + VPCI_CAP_BAR, PCI_CFGBAR, &c_cap.bar);
271 if (rc || vpci_read_bswap32(pos + VPCI_CAP_OFFSET, PCI_CFGBAR, &c_cap.off)) {
272 puts("Failed to read PCI common configuration");
273 return -EIO;
274 }
275
276 /* Device capabilities */
277 pos = virtio_pci_find_cap_pos(VPCI_CAP_DEVICE_CFG);
278 if (!pos) {
279 puts("Failed to locate PCI device configuration");
280 return 1;
281 }
282
283 rc = vpci_read_byte(pos + VPCI_CAP_BAR, PCI_CFGBAR, &d_cap.bar);
284 if (rc || vpci_read_bswap32(pos + VPCI_CAP_OFFSET, PCI_CFGBAR, &d_cap.off)) {
285 puts("Failed to read PCI device configuration");
286 return -EIO;
287 }
288
289 /* Notification capabilities */
290 pos = virtio_pci_find_cap_pos(VPCI_CAP_NOTIFY_CFG);
291 if (!pos) {
292 puts("Failed to locate PCI notification configuration");
293 return 1;
294 }
295
296 rc = vpci_read_byte(pos + VPCI_CAP_BAR, PCI_CFGBAR, &n_cap.bar);
297 if (rc || vpci_read_bswap32(pos + VPCI_CAP_OFFSET, PCI_CFGBAR, &n_cap.off)) {
298 puts("Failed to read PCI notification configuration");
299 return -EIO;
300 }
301
302 rc = vpci_read_bswap32(pos + VPCI_N_CAP_MULT, PCI_CFGBAR, &notify_mult);
303 if (rc) {
304 puts("Failed to read notification queue configuration");
305 return -EIO;
306 }
307
308 return 0;
309 }
310
311 static int enable_pci_bus_master(void)
312 {
313 uint16_t cmd_reg;
314
315 if (vpci_read_bswap16(PCI_CMD_REG, PCI_CFGBAR, &cmd_reg)) {
316 puts("Failed to read PCI command register");
317 return -EIO;
318 }
319
320 if (vpci_bswap16_write(PCI_CMD_REG, PCI_CFGBAR, cmd_reg | PCI_BUS_MASTER_MASK)) {
321 puts("Failed to enable PCI bus mastering");
322 return -EIO;
323 }
324
325 return 0;
326 }
327
328 bool virtio_pci_is_supported(VDev *vdev)
329 {
330 if (vdev->vendor_id == PCI_VENDOR_VIRTIO) {
331 switch (vdev->dev_type) {
332 case VIRTIO_ID_BLOCK:
333 return true;
334 default:
335 return false;
336 }
337 }
338
339 return false;
340 }
341
342 int virtio_pci_setup(VDev *vdev)
343 {
344 VRing *vr;
345 int rc;
346 uint8_t status;
347 int i = 0;
348
349 vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
350 vdev->cmd_vr_idx = 0;
351
352 if (!virtio_pci_is_supported(vdev)) {
353 puts("Virtio PCI unsupported for this device ID");
354 return -ENODEV;
355 }
356
357 if (virtio_pci_read_pci_cap_config()) {
358 puts("Invalid virtio PCI capabilities");
359 return -EIO;
360 }
361
362 if (enable_pci_bus_master()) {
363 return -EIO;
364 }
365
366 if (virtio_reset(vdev)) {
367 return -EIO;
368 }
369
370 status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
371 if (virtio_pci_set_status(status)) {
372 puts("Virtio-pci device Failed to ACKNOWLEDGE");
373 return -EIO;
374 }
375
376 vdev->guest_features[1] = VIRTIO_F_VERSION_1;
377 if (virtio_pci_negotiate()) {
378 panic("Virtio feature negotiation failed!");
379 }
380
381 switch (vdev->dev_type) {
382 case VIRTIO_ID_BLOCK:
383 vdev->nr_vqs = 1;
384 vdev->cmd_vr_idx = 0;
385 virtio_pci_get_blk_config();
386 break;
387 default:
388 puts("Unsupported virtio device");
389 return -ENODEV;
390 }
391
392 status |= VIRTIO_CONFIG_S_DRIVER;
393 rc = virtio_pci_set_status(status);
394 if (rc) {
395 puts("Set status failed");
396 return -EIO;
397 }
398
399 /* Configure virt-queues for pci */
400 for (i = 0; i < vdev->nr_vqs; i++) {
401 uint16_t vq_size;
402 uint16_t vq_notify;
403 VqInfo info = {
404 .queue = (unsigned long long) virtio_get_ring_area(i),
405 .align = KVM_S390_VIRTIO_RING_ALIGN,
406 .index = i,
407 .num = 0,
408 };
409
410 vr = &vdev->vrings[i];
411
412 if (vpci_set_selected_vq(i)) {
413 puts("Failed to set selected virt-queue");
414 return -EIO;
415 }
416
417 if (vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
418 printf("Failed to read virt-queue %d size\n", i);
419 return -EIO;
420 }
421
422 info.num = vq_size;
423
424 if (vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar, &vq_notify)) {
425 printf("Failed to read virt-queue %d notify offset\n", i);
426 return -EIO;
427 }
428
429 vr->pci_notify = vq_notify;
430 vring_init(vr, &info);
431
432 rc = set_pci_vq_addr(VPCI_C_OFFSET_Q_DESCLO, vr->desc);
433 rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_AVAILLO, vr->avail);
434 rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_USEDLO, vr->used);
435 if (rc) {
436 puts("Failed to configure virt-queue address");
437 return -EIO;
438 }
439
440 if (vpci_set_queue_enable(true)) {
441 puts("Failed to set virt-queue enabled");
442 return -EIO;
443 }
444 }
445
446 status |= VIRTIO_CONFIG_S_FEATURES_OK | VIRTIO_CONFIG_S_DRIVER_OK;
447 return virtio_pci_set_status(status);
448 }
449
450 int virtio_pci_setup_device(void)
451 {
452 VDev *vdev = virtio_get_device();
453
454 if (enable_pci_function(&vdev->pci_fh)) {
455 puts("Failed to enable PCI function");
456 return -ENODEV;
457 }
458
459 return 0;
460 }