On 10/12/2025 21.54, [email protected] wrote:
From: Jared Rossi <[email protected]>
Separate the CCW specific virtio routines and create generic wrappers for easier
reuse of existing virtio functions with non-CCW devices.
Signed-off-by: Jared Rossi <[email protected]>
---
...
diff --git a/pc-bios/s390-ccw/virtio-ccw.c b/pc-bios/s390-ccw/virtio-ccw.c
new file mode 100644
index 0000000000..e121826625
--- /dev/null
+++ b/pc-bios/s390-ccw/virtio-ccw.c
@@ -0,0 +1,242 @@
+/*
+ * Virtio functionality for CCW devices
+ *
+ * Copyright (c) 2013 Alexander Graf <[email protected]>
+ * Copyright 2025 IBM Corp. Author(s): Jared Rossi <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include <string.h>
+#include "s390-ccw.h"
+#include "cio.h"
+#include "virtio.h"
+#include "virtio-ccw.h"
+#include "virtio-scsi.h"
+#include "bswap.h"
+#include "helper.h"
+#include "s390-time.h"
+
+/* virtio spec v1.0 para 4.3.3.2 */
+static long kvm_hypercall(unsigned long nr, unsigned long param1,
+ unsigned long param2, unsigned long param3)
+{
+ register unsigned long r_nr asm("1") = nr;
+ register unsigned long r_param1 asm("2") = param1;
+ register unsigned long r_param2 asm("3") = param2;
+ register unsigned long r_param3 asm("4") = param3;
+ register long retval asm("2");
+
+ asm volatile ("diag %%r2,%%r4,0x500"
+ : "=d" (retval)
+ : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
+ : "memory", "cc");
+
+ return retval;
+}
+
+static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
+{
+ Ccw1 ccw = {};
+
+ ccw.cmd_code = cmd;
+ ccw.cda = (long)ptr;
+ ccw.count = len;
+
+ if (sli) {
+ ccw.flags |= CCW_FLAG_SLI;
+ }
+
+ return do_cio(vdev->schid, vdev->senseid.cu_type, ptr2u32(&ccw), CCW_FMT1);
+}
+
+bool virtio_ccw_is_supported(SubChannelId schid)
+{
+ VDev *vdev = virtio_get_device();
> + vdev->schid = schid;
At the calling site (virtio_ccw_setup), you're doing:
if (!virtio_ccw_is_supported(vdev->schid)) ...
i.e. vdev->schid is already set up, and you already have a pointer to vdev
there. So I think it would make more sense to replace the "schid" parameter
of this function here to a "vdev" pointer, and drop the call to
virtio_get_device() here, and not to re-assign vdev->schid here.
+ memset(&vdev->senseid, 0, sizeof(vdev->senseid));
+
+ /*
+ * Run sense id command.
+ * The size of the senseid data differs between devices (notably,
+ * between virtio devices and dasds), so specify the largest possible
+ * size and suppress the incorrect length indication for smaller sizes.
+ */
+ if (run_ccw(vdev, CCW_CMD_SENSE_ID, &vdev->senseid, sizeof(vdev->senseid),
+ true)) {
+ return false;
+ }
+
+ vdev->dev_type = vdev->senseid.cu_model;
+
+ if (vdev->senseid.cu_type == 0x3832) {
+ switch (vdev->dev_type) {
+ case VIRTIO_ID_BLOCK:
+ case VIRTIO_ID_SCSI:
+ case VIRTIO_ID_NET:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
...
+int virtio_ccw_setup(VDev *vdev)
+{
+ int i, cfg_size = 0;
+ uint8_t status;
+ struct VirtioFeatureDesc {
+ uint32_t features;
+ uint8_t index;
+ } __attribute__((packed)) feats;
+
+ if (!virtio_ccw_is_supported(vdev->schid)) {
+ puts("Virtio unsupported for this device ID");
+ return -ENODEV;
+ }
+ /* device ID has been established now */
+
+ vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
+ vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
+
+ virtio_reset(vdev);
+
+ status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
+ if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+ puts("Could not write ACKNOWLEDGE status to host");
+ return -EIO;
+ }
+
+ switch (vdev->dev_type) {
+ case VIRTIO_ID_NET:
+ vdev->nr_vqs = 2;
+ vdev->cmd_vr_idx = 0;
+ cfg_size = sizeof(vdev->config.net);
+ break;
+ case VIRTIO_ID_BLOCK:
+ vdev->nr_vqs = 1;
+ vdev->cmd_vr_idx = 0;
+ cfg_size = sizeof(vdev->config.blk);
+ break;
+ case VIRTIO_ID_SCSI:
+ vdev->nr_vqs = 3;
+ vdev->cmd_vr_idx = VR_REQUEST;
+ cfg_size = sizeof(vdev->config.scsi);
+ break;
+ default:
+ puts("Unsupported virtio device");
+ return -ENODEV;
+ }
+
+ status |= VIRTIO_CONFIG_S_DRIVER;
+ if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+ puts("Could not write DRIVER status to host");
+ return -EIO;
+ }
+
+ /* Feature negotiation */
+ for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
+ feats.features = 0;
+ feats.index = i;
+ if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
+ puts("Could not get features bits");
+ return -EIO;
+ }
+
+ vdev->guest_features[i] &= bswap32(feats.features);
+ feats.features = bswap32(vdev->guest_features[i]);
+ if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) {
+ puts("Could not set features bits");
+ return -EIO;
+ }
+ }
+
+ if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
+ puts("Could not get virtio device configuration");
+ return -EIO;
+ }
+
+ for (i = 0; i < vdev->nr_vqs; i++) {
+ VqInfo info = {
+ .queue = (unsigned long long) virtio_get_ring_area() + (i *
VIRTIO_RING_SIZE),
Would it make sense to add a "ring_num" parameter to virtio_get_ring_area(),
so that you could call virtio_get_ring_area(i) here instead?
virtio_get_ring_area() would then look like this:
char *virtio_get_ring_area(int ring_num)
{
return ring_area + ring_num * VIRTIO_RING_SIZE;
}
?
+ .align = KVM_S390_VIRTIO_RING_ALIGN,
+ .index = i,
+ .num = 0,
+ };
+ VqConfig config = {
+ .index = i,
+ .num = 0,
+ };
+
+ if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
+ false)) {
+ puts("Could not get virtio device VQ config");
+ return -EIO;
+ }
+ info.num = config.num;
+ vring_init(&vdev->vrings[i], &info);
+ vdev->vrings[i].schid = vdev->schid;
+ if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
+ puts("Cannot set VQ info");
+ return -EIO;
+ }
+ }
+
+ status |= VIRTIO_CONFIG_S_DRIVER_OK;
+ if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+ puts("Could not write DRIVER_OK status to host");
+ return -EIO;
+ }
+
+ return 0;
+}
...
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 0f4f201038..0488b3a07e 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -2,6 +2,7 @@
* Virtio driver bits
*
* Copyright (c) 2013 Alexander Graf <[email protected]>
+ * Copyright 2025 IBM Corp. Author(s): Jared Rossi <[email protected]>
I assume you wanted to put Authors on a separate line?
Thomas