From: Jared Rossi <jrossi@linux.ibm.com>
Call Logical Processor (CLP) Architecture is used for managing PCI functions on
s390x. Define and include the structures and routines needed to interact with
PCI devices during IPL.
Headers in ~/qemu/include/hw are not normally visible and must be included
using a relative path. Due to this, the QEMU_PACKED macro must also be defined
here.
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
---
pc-bios/s390-ccw/clp.h | 24 +++++++++
pc-bios/s390-ccw/clp.c | 106 ++++++++++++++++++++++++++++++++++++++
pc-bios/s390-ccw/Makefile | 2 +-
3 files changed, 131 insertions(+), 1 deletion(-)
create mode 100644 pc-bios/s390-ccw/clp.h
create mode 100644 pc-bios/s390-ccw/clp.c
diff --git a/pc-bios/s390-ccw/clp.h b/pc-bios/s390-ccw/clp.h
new file mode 100644
index 0000000000..cb130e5e90
--- /dev/null
+++ b/pc-bios/s390-ccw/clp.h
@@ -0,0 +1,24 @@
+/*
+ * Call Logical Processor (CLP) architecture definitions
+ *
+ * Copyright 2025 IBM Corp.
+ * Author(s): Jared Rossi <jrossi@linux.ibm.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef CLP_H
+#define CLP_H
+
+#ifndef QEMU_PACKED
+#define QEMU_PACKED __attribute__((packed))
+#endif
+
+#include <stdint.h>
+#include "../../include/hw/s390x/s390-pci-clp.h"
+
+int clp_pci(void *data);
+int enable_pci_function(uint32_t *fhandle);
+int enumerate_pci_functions(void);
+
+#endif
diff --git a/pc-bios/s390-ccw/clp.c b/pc-bios/s390-ccw/clp.c
new file mode 100644
index 0000000000..45d496fc18
--- /dev/null
+++ b/pc-bios/s390-ccw/clp.c
@@ -0,0 +1,106 @@
+/*
+ * Call Logical Processor (CLP) architecture
+ *
+ * Copyright 2025 IBM Corp.
+ * Author(s): Jared Rossi <jrossi@linux.ibm.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "clp.h"
+#include <stdio.h>
+#include <string.h>
+
+int clp_pci(void *data)
+{
+ struct { uint8_t _[2048]; } *req = data;
+ int cc = 3;
+
+ asm volatile (
+ " .insn rrf,0xb9a00000,0,%[req],0,2\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "+d" (cc), "+m" (*req)
+ : [req] "a" (req)
+ : "cc");
+ return cc;
+}
+
+/*
+ * Get the PCI function entry for a given function ID
+ * Return 0 on success, 1 if the FID is not found, or a negative RC on error
+ */
+int find_pci_function(uint32_t fid, ClpFhListEntry *entry)
+{
+ int rc;
+ int count = 0;
+ int limit = PCI_MAX_FUNCTIONS;
+ ClpReqRspListPci rrb;
+
+ rrb.request.hdr.len = 32;
+ rrb.request.hdr.cmd = 0x02;
+ rrb.request.resume_token = 0;
+ rrb.response.hdr.len = sizeof(ClpRspListPci);
+
+ do {
+ rc = clp_pci(&rrb);
+ if (rc) {
+ return -rc;
+ }
+
+ if (rrb.response.hdr.rsp != 0x0010) {
+ printf("Failed to list PCI functions: %x", rrb.response.hdr.rsp);
+ return -1;
+ }
+
+ /* Resume token set when max enteries are returned */
+ if (rrb.response.resume_token) {
+ count = CLP_FH_LIST_NR_ENTRIES;
+ rrb.request.resume_token = rrb.response.resume_token;
+ } else {
+ count = (rrb.response.hdr.len - 32) / sizeof(ClpFhListEntry);
+ }
+
+ limit -= count;
+
+ for (int i = 0; i < count; i++) {
+ if (rrb.response.fh_list[i].fid == fid) {
+ memcpy(entry, &rrb.response.fh_list[i], sizeof(ClpFhListEntry));
+ return 0;
+ }
+ }
+
+ } while (rrb.request.resume_token && limit);
+
+ return 1;
+}
+
+/*
+ * Enable the PCI function associated with a given handle
+ * Return 0 on success or a negative RC on error
+ */
+int enable_pci_function(uint32_t *fhandle)
+{
+ ClpReqRspSetPci rrb;
+ int rc;
+
+ rrb.request.hdr.len = 32;
+ rrb.request.hdr.cmd = 0x05;
+ rrb.request.fh = *fhandle;
+ rrb.request.oc = 0;
+ rrb.request.ndas = 1;
+ rrb.response.hdr.len = 32;
+
+ rc = clp_pci(&rrb);
+ if (rc) {
+ return -rc;
+ }
+
+ if (rrb.response.hdr.rsp != 0x0010) {
+ printf("Failed to enable PCI function: %x", rrb.response.hdr.rsp);
+ return -1;
+ }
+
+ *fhandle = rrb.response.fh;
+ return 0;
+}
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 3577ac381a..89a42ae506 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
+ virtio-ccw.o clp.o
SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
--
2.49.0