Hi Jared,

On 10/20/2025 9:20 AM, [email protected] wrote:
From: Jared Rossi<[email protected]>

Define selected s390x PCI instructions and extend IPLB to allow PCI devices.

Signed-off-by: Jared Rossi<[email protected]>
---
  include/hw/s390x/ipl/qipl.h |   9 ++
  pc-bios/s390-ccw/pci.h      |  77 +++++++++++++++
  pc-bios/s390-ccw/pci.c      | 191 ++++++++++++++++++++++++++++++++++++
  pc-bios/s390-ccw/Makefile   |   2 +-
  4 files changed, 278 insertions(+), 1 deletion(-)
  create mode 100644 pc-bios/s390-ccw/pci.h
  create mode 100644 pc-bios/s390-ccw/pci.c

diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
index aadab87c2e..efd7b3797c 100644
--- a/include/hw/s390x/ipl/qipl.h
+++ b/include/hw/s390x/ipl/qipl.h
@@ -104,6 +104,14 @@ struct IplBlockQemuScsi {
  } QEMU_PACKED;
  typedef struct IplBlockQemuScsi IplBlockQemuScsi;
+struct IplBlockPci {
+    uint32_t reserved0[80];
+    uint8_t  opt;
+    uint8_t  reserved1[3];
+    uint32_t fid;
+} QEMU_PACKED;
+typedef struct IplBlockPci IplBlockPci;
+
  union IplParameterBlock {
      struct {
          uint32_t len;
@@ -119,6 +127,7 @@ union IplParameterBlock {
              IplBlockFcp fcp;
              IPLBlockPV pv;
              IplBlockQemuScsi scsi;
+            IplBlockPci pci;
          };
      } QEMU_PACKED;
      struct {
diff --git a/pc-bios/s390-ccw/pci.h b/pc-bios/s390-ccw/pci.h
new file mode 100644
index 0000000000..b5dc5bff35
--- /dev/null
+++ b/pc-bios/s390-ccw/pci.h
@@ -0,0 +1,77 @@
+/*
+ * s390x PCI definitions
+ *
+ * Copyright 2025 IBM Corp.
+ * Author(s): Jared Rossi<[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef PCI_H
+#define PCI_H
+
+#include <stdint.h>
+#include "clp.h"
+
+#define ZPCI_CREATE_REQ(handle, space, len)                    \
+    ((uint64_t) handle << 32 | space << 16 | len)
+
+union register_pair {
+    unsigned __int128 pair;
+    struct {
+        unsigned long even;
+        unsigned long odd;
+    };
+};
+
+#define PCIFIB_FC_ENABLED      0x80
+#define PCIFIB_FC_ERROR        0x40
+#define PCIFIB_FC_BLOCKED      0x20
+#define PCIFIB_FC_DMAREG       0x10
+
+#define PCIST_DISABLED         0x0
+#define PCIST_ENABLED          0x1
+
+#define PCI_CAPABILITY_LIST    0x34 /* Offset of first capability list entry */
+
+struct PciFib {
+    uint32_t reserved0[2];
+    uint8_t fcflags;
+    uint8_t reserved1[3];
+    uint32_t reserved2;
+    uint64_t pba;
+    uint64_t pal;
+    uint64_t iota;
+    uint16_t isc:4;
+    uint16_t noi:12;
+    uint8_t reserved3:2;
+    uint8_t aibvo:6;
+    uint8_t s:1;
+    uint8_t reserved4:1;
+    uint8_t aisbo:6;
+    uint32_t reserved5;
+    uint64_t aibv;
+    uint64_t aisb;
+    uint64_t fmba;
+    uint32_t reserved6[2];
+};
+typedef struct PciFib PciFib;
+
+struct PciDevice {
+    uint16_t device_id;
+    uint16_t vendor_id;
+    uint32_t fid;
+    uint32_t fhandle;
+    uint8_t status;
+    PciFib fib;
+};
+typedef struct PciDevice PciDevice;
+
+int pci_write(uint32_t fhandle, uint64_t offset, uint64_t data, uint8_t len);
+int pci_read(uint32_t fhandle, uint64_t offset, uint8_t picas, void *buf, 
uint8_t len);
+uint8_t find_cap_pos(uint32_t fhandle, uint64_t cfg_type);
+int pci_dev_enable(PciDevice *pcidev);
+int get_fib(PciFib *fib, uint32_t fhandle);
+int set_fib(PciFib *fib, uint32_t fhandle, uint8_t dma_as, uint8_t opcontrol);
+
+#endif
diff --git a/pc-bios/s390-ccw/pci.c b/pc-bios/s390-ccw/pci.c
new file mode 100644
index 0000000000..f776bc064c
--- /dev/null
+++ b/pc-bios/s390-ccw/pci.c
@@ -0,0 +1,191 @@
+/*
+ * 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 <stdio.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;
+    uint64_t __data = 0x92;
+

Why is __data initialized to 0x92?


+    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 */
+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;
+
+    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 */
+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 */
+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, uint64_t data, uint8_t len)
+{
+
+    uint64_t req = ZPCI_CREATE_REQ(fhandle, 4, len);

This assumes that we will only read to BAR 4? I think we should pass the PCIAS here as well if we want to generalize this function?


+    uint8_t status;
+    int rc;
+
+    rc = pcistg(data, req, offset, &status);
+    if (rc == 1) {
+        return status;
+    } else if (rc) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int pci_read(uint32_t fhandle, uint64_t offset, uint8_t picas, void *buf, 
uint8_t len)
+{
+    uint64_t req;
+    uint64_t data;
+    uint8_t status;
+    int readlen;
+    int i = 0;
+    int rc = 0;
+
+    while (len > 0 && !rc) {
+        data = 0;
+        readlen = len > 8 ? 8 : len;
+        req = ZPCI_CREATE_REQ(fhandle, picas, readlen);
+        rc = pcilg(&data, req, offset + (i * 8), &status);

Shouldn't this be offset + (i * readlen)? but I guess this works because we will only increment i on reads greater than 8 bytes. Maybe we could try to simplify this and have a single pci_read function and several other helper functions that uses pci_read to read sizes of 1/2/4/8 bytes. For reads greater than 8 bytes we can have another function (similar to zpci_memcpy_from_io, in the kernel). From what I can tell most of the pci_read calls reads are 8 bytes in the rest of the patches, except maybe for one case which reads greater than 8?


+        ((uint64_t *)buf)[i] = data;
+        len -= readlen;
+        i++;
+    }
+
+    if (rc == 1) {
+        return status;
+    } else if (rc) {
+        return rc;
+    }
+
+    return 0;
+}
+
+/*
+ * Find the position of the capability config within PCI configuration
+ * space for a given cfg type.  Return the position if found, otherwise 0.
+ */
+uint8_t find_cap_pos(uint32_t fhandle, uint64_t cfg_type) {
+    uint64_t req, next, cfg;
+    uint8_t status;
+    int rc;
+
+    req = ZPCI_CREATE_REQ(fhandle, 0xf, 1);
+    rc = pcilg(&next, req, PCI_CAPABILITY_LIST, &status);
+    rc = pcilg(&cfg, req, next + 3, &status);

Why are we reading next + 3 into cfg? If I understand this correctly next will be the address of the first capability in the linked list, and so we should just read the first byte from next to get the capability id? I think we should have helper function like qpci_find_capability to find the capabilities?


+
+    while (!rc && (cfg != cfg_type) && next) {
+        rc = pcilg(&next, req, next + 1, &status);
+        rc = pcilg(&cfg, req, next + 3, &status);

Same question here?


+    }
+
+    return rc ? 0 : next;
+}
+

[..snip..]



Reply via email to