pc-bios/s390-ccw: Introduce virtio-pci functions
Define common functionality for interacting with virtio-pci devices. Signed-off-by: Jared Rossi <jrossi@linux.ibm.com> Acked-by: Matthew Rosato <mjrosato@linux.ibm.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Eric Farman <farman@linux.ibm.com> Message-ID: <20260309003601.242634-12-jrossi@linux.ibm.com> Signed-off-by: Thomas Huth <thuth@redhat.com>
Jared Rossi committed
Mar 8, 2026 at 20:35 UTC
40d80aedd5a109a74a22a84c8d17a864f38a791d
4 files changed
+251
-1
pc-bios/s390-ccw/Makefile
+1
-1
@@ -35,7 +35,7 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d
35
36
OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o netmain.o \
37
virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o \
38
- virtio-ccw.o clp.o pci.o
38
+ virtio-ccw.o clp.o pci.o virtio-pci.o
39
40
SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
41
pc-bios/s390-ccw/virtio-pci.c
new
+167
@@ -0,0 +1,167 @@
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
+uint16_t q_notify_offset;
25
+
26
+static int virtio_pci_set_status(uint8_t status)
27
+{
28
+ int rc = vpci_write_byte(c_cap.off + VPCI_C_OFFSET_STATUS, c_cap.bar, status);
29
+ if (rc) {
30
+ puts("Failed to write virtio-pci status");
31
+ return -EIO;
32
+ }
33
+
34
+ return 0;
35
+}
36
+
37
+static int virtio_pci_get_status(uint8_t *status)
38
+{
39
+ int rc = vpci_read_byte(c_cap.off + VPCI_C_OFFSET_STATUS, c_cap.bar, status);
40
+ if (rc) {
41
+ puts("Failed to read virtio-pci status");
42
+ return -EIO;
43
+ }
44
+
45
+ return 0;
46
+}
47
+
48
+/* virtio spec v1.3 section 4.1.2.1 */
49
+void virtio_pci_id2type(VDev *vdev, uint16_t device_id)
50
+{
51
+ switch (device_id) {
52
+ case 0x1042:
53
+ case 0x1001:
54
+ vdev->dev_type = VIRTIO_ID_BLOCK;
55
+ break;
56
+ default:
57
+ vdev->dev_type = 0;
58
+ }
59
+}
60
+
61
+int virtio_pci_reset(VDev *vdev)
62
+{
63
+ int rc;
64
+ uint8_t status = 0;
65
+
66
+ rc = virtio_pci_set_status(status);
67
+ rc |= virtio_pci_get_status(&status);
68
+
69
+ if (rc || status) {
70
+ puts("Failed to reset virtio-pci device");
71
+ return 1;
72
+ }
73
+
74
+ return 0;
75
+}
76
+
77
+long virtio_pci_notify(int vq_id)
78
+{
79
+ uint32_t offset = n_cap.off + notify_mult * q_notify_offset;
80
+ return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vq_id);
81
+}
82
+
83
+/*
84
+ * Wrappers to byte swap common data sizes then write
85
+ */
86
+int vpci_write_byte(uint64_t offset, uint8_t pcias, uint8_t data)
87
+{
88
+ return pci_write(virtio_get_device()->pci_fh, offset, pcias, (uint64_t) data, 1);
89
+}
90
+
91
+int vpci_bswap16_write(uint64_t offset, uint8_t pcias, uint16_t data)
92
+{
93
+ uint64_t le_data = bswap16(data);
94
+ return pci_write(virtio_get_device()->pci_fh, offset, pcias, le_data, 2);
95
+}
96
+
97
+int vpci_bswap32_write(uint64_t offset, uint8_t pcias, uint32_t data)
98
+{
99
+ uint64_t le_data = bswap32(data);
100
+ return pci_write(virtio_get_device()->pci_fh, offset, pcias, le_data, 4);
101
+}
102
+
103
+int vpci_bswap64_write(uint64_t offset, uint8_t pcias, uint64_t data)
104
+{
105
+ uint64_t le_data = bswap64(data);
106
+ return pci_write(virtio_get_device()->pci_fh, offset, pcias, le_data, 8);
107
+}
108
+
109
+/*
110
+ * Wrappers to read common data sizes then byte swap
111
+ */
112
+int vpci_read_byte(uint64_t offset, uint8_t pcias, uint8_t *buf)
113
+{
114
+ return pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, 1);
115
+}
116
+
117
+int vpci_read_bswap16(uint64_t offset, uint8_t pcias, uint16_t *buf)
118
+{
119
+ int rc = pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, 2);
120
+ *buf = bswap16(*buf);
121
+ return rc;
122
+}
123
+
124
+int vpci_read_bswap32(uint64_t offset, uint8_t pcias, uint32_t *buf)
125
+{
126
+ int rc = pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, 4);
127
+ *buf = bswap32(*buf);
128
+ return rc;
129
+}
130
+
131
+int vpci_read_bswap64(uint64_t offset, uint8_t pcias, uint64_t *buf)
132
+{
133
+ int rc = pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, 8);
134
+ *buf = bswap64(*buf);
135
+ return rc;
136
+}
137
+
138
+/*
139
+ * Read to an arbitrary length buffer without byte swapping
140
+ */
141
+int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len)
142
+{
143
+ uint8_t readlen;
144
+ int rc;
145
+ int remaining = len;
146
+
147
+ /* Read bytes in powers of 2, up to a maximum of 8 bytes per read */
148
+ while (remaining) {
149
+ for (int i = 3; i >= 0; i--) {
150
+ readlen = 1 << i;
151
+ if (remaining >= readlen) {
152
+ break;
153
+ }
154
+ }
155
+
156
+ rc = pci_read(virtio_get_device()->pci_fh, offset, pcias, buf, readlen);
157
+ if (rc) {
158
+ return -1;
159
+ }
160
+
161
+ remaining -= readlen;
162
+ buf += readlen;
163
+ offset += readlen;
164
+ }
165
+
166
+ return 0;
167
+}
pc-bios/s390-ccw/virtio-pci.h
new
+80
@@ -0,0 +1,80 @@
1
+/*
2
+ * Definitions 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
+#ifndef VIRTIO_PCI_H
11
+#define VIRTIO_PCI_H
12
+
13
+/* Common configuration */
14
+#define VPCI_CAP_COMMON_CFG 1
15
+/* Notifications */
16
+#define VPCI_CAP_NOTIFY_CFG 2
17
+/* ISR access */
18
+#define VPCI_CAP_ISR_CFG 3
19
+/* Device specific configuration */
20
+#define VPCI_CAP_DEVICE_CFG 4
21
+/* PCI configuration access */
22
+#define VPCI_CAP_PCI_CFG 5
23
+/* Additional shared memory capability */
24
+#define VPCI_CAP_SHARED_MEMORY_CFG 8
25
+/* PCI vendor data configuration */
26
+#define VPCI_CAP_VENDOR_CFG 9
27
+
28
+/* Offsets within capability header */
29
+#define VPCI_CAP_VNDR 0
30
+#define VPCI_CAP_NEXT 1
31
+#define VPCI_CAP_LEN 2
32
+#define VPCI_CAP_CFG_TYPE 3
33
+#define VPCI_CAP_BAR 4
34
+#define VPCI_CAP_OFFSET 8
35
+#define VPCI_CAP_LENGTH 12
36
+
37
+#define VPCI_N_CAP_MULT 16 /* Notify multiplier, VPCI_CAP_NOTIFY_CFG only */
38
+
39
+/* Common Area Offsets for virtio-pci queue */
40
+#define VPCI_C_OFFSET_DFSELECT 0
41
+#define VPCI_C_OFFSET_DF 4
42
+#define VPCI_C_OFFSET_GFSELECT 8
43
+#define VPCI_C_OFFSET_GF 12
44
+#define VPCI_C_COMMON_NUMQ 18
45
+#define VPCI_C_OFFSET_STATUS 20
46
+#define VPCI_C_OFFSET_Q_SELECT 22
47
+#define VPCI_C_OFFSET_Q_SIZE 24
48
+#define VPCI_C_OFFSET_Q_ENABLE 28
49
+#define VPCI_C_OFFSET_Q_NOFF 30
50
+#define VPCI_C_OFFSET_Q_DESCLO 32
51
+#define VPCI_C_OFFSET_Q_DESCHI 36
52
+#define VPCI_C_OFFSET_Q_AVAILLO 40
53
+#define VPCI_C_OFFSET_Q_AVAILHI 44
54
+#define VPCI_C_OFFSET_Q_USEDLO 48
55
+#define VPCI_C_OFFSET_Q_USEDHI 52
56
+
57
+#define VIRTIO_F_VERSION_1 1 /* Feature bit 32 */
58
+
59
+struct VirtioPciCap {
60
+ uint8_t bar; /* Which PCIAS it's in */
61
+ uint32_t off; /* Offset within bar */
62
+};
63
+typedef struct VirtioPciCap VirtioPciCap;
64
+
65
+void virtio_pci_id2type(VDev *vdev, uint16_t device_id);
66
+int virtio_pci_reset(VDev *vdev);
67
+long virtio_pci_notify(int vq_id);
68
+
69
+int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len);
70
+int vpci_read_bswap64(uint64_t offset, uint8_t pcias, uint64_t *buf);
71
+int vpci_read_bswap32(uint64_t offset, uint8_t pcias, uint32_t *buf);
72
+int vpci_read_bswap16(uint64_t offset, uint8_t pcias, uint16_t *buf);
73
+int vpci_read_byte(uint64_t offset, uint8_t pcias, uint8_t *buf);
74
+
75
+int vpci_bswap64_write(uint64_t offset, uint8_t pcias, uint64_t data);
76
+int vpci_bswap32_write(uint64_t offset, uint8_t pcias, uint32_t data);
77
+int vpci_bswap16_write(uint64_t offset, uint8_t pcias, uint16_t data);
78
+int vpci_write_byte(uint64_t offset, uint8_t pcias, uint8_t data);
79
+
80
+#endif
pc-bios/s390-ccw/virtio.h
+3
@@ -18,6 +18,8 @@
18
#define VIRTIO_CONFIG_S_DRIVER 2
19
/* Driver has used its parts of the config, and is happy */
20
#define VIRTIO_CONFIG_S_DRIVER_OK 4
21
+/* Feature negotiation complete */
22
+#define VIRTIO_CONFIG_S_FEATURES_OK 8
23
/* We've given up on this device. */
24
#define VIRTIO_CONFIG_S_FAILED 0x80
25
@@ -255,6 +257,7 @@ struct VDev {
257
uint8_t scsi_dev_heads;
258
bool scsi_device_selected;
259
ScsiDevice selected_scsi_device;
260
+ uint32_t pci_fh;
261
uint32_t max_transfer;
262
uint32_t guest_features[2];
263
};