On 1/27/2026 8:15 AM, [email protected] wrote:
From: Jared Rossi <[email protected]>
Define selected s390x PCI instructions.
Signed-off-by: Jared Rossi <[email protected]>
---
pc-bios/s390-ccw/Makefile | 2 +-
pc-bios/s390-ccw/pci.c | 194 ++++++++++++++++++++++++++++++++++++++
pc-bios/s390-ccw/pci.h | 80 ++++++++++++++++
3 files changed, 275 insertions(+), 1 deletion(-)
create mode 100644 pc-bios/s390-ccw/pci.c
create mode 100644 pc-bios/s390-ccw/pci.h
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 9c29548f84..a62fc9d766 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -35,7 +35,7 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d
OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o netmain.o \
virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o \
- virtio-ccw.o clp.o
+ virtio-ccw.o clp.o pci.o
SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
diff --git a/pc-bios/s390-ccw/pci.c b/pc-bios/s390-ccw/pci.c
new file mode 100644
index 0000000000..9656be45ca
--- /dev/null
+++ b/pc-bios/s390-ccw/pci.c
@@ -0,0 +1,194 @@
+/*
+ * s390x PCI funcionality
+ *
+ * Copyright 2025 IBM Corp.
+ * Author(s): Jared Rossi <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "clp.h"
+#include "pci.h"
+#include "bswap.h"
+#include <stdio.h>
+#include <stdbool.h>
+
+/* PCI load */
+static inline int pcilg(uint64_t *data, uint64_t req, uint64_t offset,
+ uint8_t *status)
+{
+ union register_pair req_off = {.even = req, .odd = offset};
+ int cc = -1;
Nit: Setting cc = -1 doesn't make any difference since the cc gets
overwritten and the pcilg will return cc > 0.
+ uint64_t __data;
+
+ asm volatile (
+ " .insn rre,0xb9d20000,%[data],%[req_off]\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "+d" (cc), [data] "=d" (__data),
+ [req_off] "+d" (req_off.pair) :: "cc");
+ *status = req_off.even >> 24 & 0xff;
+ *data = __data;
+ return cc;
+}
+
+/* PCI store */
+static inline int pcistg(uint64_t data, uint64_t req, uint64_t offset,
+ uint8_t *status)
+{
+ union register_pair req_off = {.even = req, .odd = offset};
+ int cc = -1;
Nit: Same as pcilg.
+
+ asm volatile (
+ " .insn rre,0xb9d00000,%[data],%[req_off]\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "+d" (cc), [req_off] "+d" (req_off.pair)
+ : [data] "d" (data)
+ : "cc");
+ *status = req_off.even >> 24 & 0xff;
+ return cc;
+}
+
+/* store PCI function controls */
+static inline int stpcifc(uint64_t req, PciFib *fib, uint8_t *status)
+{
+ uint8_t cc;
+
+ asm volatile (
+ " .insn rxy,0xe300000000d4,%[req],%[fib]\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
+ : : "cc");
+ *status = req >> 24 & 0xff;
+ return cc;
+}
+
+/* modify PCI function controls */
+static inline int mpcifc(uint64_t req, PciFib *fib, uint8_t *status)
+{
+ uint8_t cc;
+
+ asm volatile (
+ " .insn rxy,0xe300000000d0,%[req],%[fib]\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
+ : : "cc");
+ *status = req >> 24 & 0xff;
+ return cc;
+}
+
+int pci_write(uint32_t fhandle, uint64_t offset, uint8_t pcias, uint64_t data,
+ uint8_t len)
+{
+
+ uint64_t req = ZPCI_CREATE_REQ(fhandle, pcias, len);
+ uint8_t status;
+ int rc;
+
+ /* len must be non-zero power of 2 with a maximum of 8 bytes per write */
+ switch (len) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ rc = pcistg(data, req, offset, &status);
+ break;
+ default:
+ rc = -1;
+ }
+
+ /* Error condition detected */
+ if (rc == 1) {
According to the architecture a return code of 0 would indicate normal
completion. But we do have error scenarios that can return error code >
1. For example an error code of 3 would indicate 'Unrecognized handle'.
May we should check for non-zero rc in this if condition...
+ printf("PCI store failed with status condition %d\n", status);
... and print both the rc and status here.
+ return -1;
+ }
+
+ return rc ? -1 : 0;
+}
+
+int pci_read(uint32_t fhandle, uint64_t offset, uint8_t pcias, void *buf,
+ uint8_t len)
+{
+ uint64_t req, data;
+ uint8_t status;
+ int rc;
+
+ req = ZPCI_CREATE_REQ(fhandle, pcias, len);
+ rc = pcilg(&data, req, offset, &status);
+
+ /* Error condition detected */
+ if (rc == 1) {
Similar to pci_write we should check for non-zero return code here? And
should do the same in pci_get_fib (stpcifc) and pci_set_fib (mpcifc)?
+ printf("PCI load failed with status condition %d\n", status);
+ return -1;
+ }
+
+ switch (len) {
+ case 1:
+ *(uint8_t *)buf = data;
+ break;
+ case 2:
+ *(uint16_t *)buf = data;
+ break;
+ case 4:
+ *(uint32_t *)buf = data;
+ break;
+ case 8:
+ *(uint64_t *)buf = data;
+ break;
+ default:
+ return -1;
+ }
+
+ return rc ? -1 : 0;
+}
+
<...snip...>