[PATCH v2 09/13] scripts/ghes_inject: add a handler for PCI/PCI-X bus error

Mauro Carvalho Chehab posted 13 patches 1 day, 20 hours ago
Maintainers: John Snow <jsnow@redhat.com>, Cleber Rosa <crosa@redhat.com>, Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
[PATCH v2 09/13] scripts/ghes_inject: add a handler for PCI/PCI-X bus error
Posted by Mauro Carvalho Chehab 1 day, 20 hours ago
Add a logic to do PCIe BUS error injection.

On Linux Kernel, despite CPER_SEC_PCI_X_BUS macro is defined for such
event, ghes.c doesn't implement support for it yet:

[16950.077494] {26}[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 1
[16950.077866] {26}[Hardware Error]: event severity: recoverable
[16950.078118] {26}[Hardware Error]:  Error 0, type: recoverable
[16950.078444] {26}[Hardware Error]:   section type: unknown, c5753963-3b84-4095-bf78-eddad3f9c9dd
[16950.078800] {26}[Hardware Error]:   section length: 0x48
[16950.079069] {26}[Hardware Error]:   00000000: 00000000 00000000 00000000 00000000  ................
[16950.079442] {26}[Hardware Error]:   00000010: 00000001 00000000 00000000 00000000  ................
[16950.079811] {26}[Hardware Error]:   00000020: 00000000 00000000 00000000 00000000  ................
[16950.080181] {26}[Hardware Error]:   00000030: 00000000 00000000 00000000 00000000  ................
[16950.080538] {26}[Hardware Error]:   00000040: 00000000 00000000                    ........

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
 MAINTAINERS              |   1 +
 scripts/ghes_inject.py   |   2 +
 scripts/pci_bus_error.py | 146 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 149 insertions(+)
 create mode 100644 scripts/pci_bus_error.py

diff --git a/MAINTAINERS b/MAINTAINERS
index a970c47dd089..1e62064a8672 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2228,6 +2228,7 @@ F: qapi/acpi-hest.json
 F: scripts/ghes_decode.py
 F: scripts/ghes_inject.py
 F: scripts/arm_processor_error.py
+F: scripts/pci_bus_error.py
 F: scripts/qmp_helper.py
 
 ppc4xx
diff --git a/scripts/ghes_inject.py b/scripts/ghes_inject.py
index 6ac917d0b5db..be2384a59b3e 100755
--- a/scripts/ghes_inject.py
+++ b/scripts/ghes_inject.py
@@ -12,6 +12,7 @@
 import sys
 
 from arm_processor_error import ArmProcessorEinj
+from pci_bus_error import PciBusError
 
 EINJ_DESC = """
 Handle ACPI GHESv2 error injection logic QEMU QMP interface.
@@ -40,6 +41,7 @@ def main():
     subparsers = parser.add_subparsers()
 
     ArmProcessorEinj(subparsers)
+    PciBusError(subparsers)
 
     args = parser.parse_args()
     if "func" in args:
diff --git a/scripts/pci_bus_error.py b/scripts/pci_bus_error.py
new file mode 100644
index 000000000000..5abfdf11c868
--- /dev/null
+++ b/scripts/pci_bus_error.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+#
+# pylint: disable=C0114,R0903
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2024 Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+
+from qmp_helper import qmp, util, cper_guid
+
+class PciBusError:
+    """
+    Implements PCI Express bus error injection via GHES
+    """
+
+    def __init__(self, subparsers):
+        """Initialize the error injection class and add subparser"""
+
+        # Valid values
+        self.valid_bits = {
+            "status": util.bit(0),
+            "type": util.bit(1),
+            "bus-id": util.bit(2),
+            "bus-addr": util.bit(3),
+            "bus-data": util.bit(4),
+            "command": util.bit(5),
+            "requestor-id": util.bit(6),
+            "completer-id": util.bit(7),
+            "target-id": util.bit(8),
+        }
+
+        self.bus_command_bits = {
+            "pci": 0,               # Bit 56 is zero
+            "pci-x": util.bit(56)
+        }
+
+        self.data = bytearray()
+
+        parser = subparsers.add_parser("pci-bus",
+                                       description="Generate PCI/PCI-X bus error CPER")
+        g_pci = parser.add_argument_group("PCI/PCI-X bus error")
+
+        valid_bits = ",".join(self.valid_bits.keys())
+        bus_command_bits = ",".join(self.bus_command_bits.keys())
+
+        g_pci.add_argument("-v", "--valid",
+                            help=f"Valid bits: {valid_bits}")
+        g_pci.add_argument("-s", "--error-status",
+                            type=lambda x: int(x, 0),
+                            help="Error Status")
+        g_pci.add_argument("-t", "--error-type",
+                            type=lambda x: int(x, 0),
+                            help="Error type")
+        g_pci.add_argument("-b", "--bus-number",
+                            type=lambda x: int(x, 0),
+                            help="Bus number")
+        g_pci.add_argument("-S", "--segment-number",
+                            type=lambda x: int(x, 0),
+                            help="Segment number")
+        g_pci.add_argument("-a", "--bus-address",
+                            type=lambda x: int(x, 0),
+                            help="Bus address")
+        g_pci.add_argument("-d", "--bus-data",
+                            type=lambda x: int(x, 0),
+                            help="Bus data")
+        g_pci.add_argument("-c", "--bus-command",
+                            help=f"bus-command: {bus_command_bits}")
+        g_pci.add_argument("-r", "--bus-requestor",
+                            type=lambda x: int(x, 0),
+                            help="Bus requestor ID")
+        g_pci.add_argument("-C", "--bus-completer",
+                            type=lambda x: int(x, 0),
+                            help="Bus completer ID")
+        g_pci.add_argument("-i", "--target-id",
+                            type=lambda x: int(x, 0),
+                            help="Target ID")
+
+        parser.set_defaults(func=self.send_cper)
+
+    def send_cper(self, args):
+        """Parse subcommand arguments and send a CPER via QMP"""
+
+        qmp_cmd = qmp(args.host, args.port, args.debug)
+
+        cper = {}
+        arg = vars(args)
+
+        # Handle global parameters
+        if args.valid:
+            valid_init = False
+            cper["valid"] = util.get_choice(name="valid",
+                                            value=args.valid,
+                                            choices=self.valid_bits)
+        else:
+            cper["valid"] = 0
+            valid_init = True
+
+        if args.bus_command:
+            cper["bus-command"] = util.get_choice(name="bus-command",
+                                                    value=args.bus_command,
+                                                    choices=self.bus_command_bits)
+        if valid_init:
+            if args.error_status:
+                cper["valid"] |= self.valid_bits["status"]
+
+            if args.error_type:
+                cper["valid"] |= self.valid_bits["type"]
+
+            if args.bus_number and args.bus_segment:
+                cper["valid"] |= self.valid_bits["bus-id"]
+
+            if args.bus_address:
+                cper["valid"] |= self.valid_bits["bus-address"]
+
+            if args.bus_data:
+                cper["valid"] |= self.valid_bits["bus-data"]
+
+            if args.bus_requestor:
+                cper["valid"] |= self.valid_bits["requestor-id"]
+
+            if args.bus_completer:
+                cper["valid"] |= self.valid_bits["completer-id"]
+
+            if args.target_id:
+                cper["valid"] |= self.valid_bits["target-id"]
+
+        util.data_add(self.data, cper["valid"], 8)
+        util.data_add(self.data, arg.get("error-status", 0), 8)
+        util.data_add(self.data, arg.get("error-type", util.bit(0)), 2)
+
+        # Bus ID
+        util.data_add(self.data, arg.get("bus-number", 0), 1)
+        util.data_add(self.data, arg.get("segment-number", 0), 1)
+
+        # Reserved
+        util.data_add(self.data, 0, 4)
+
+        util.data_add(self.data, arg.get("bus-address", 0), 8)
+        util.data_add(self.data, arg.get("bus-data", 0), 8)
+
+        util.data_add(self.data, cper.get("bus-command", 0), 8)
+
+        util.data_add(self.data, arg.get("bus-requestor", 0), 8)
+        util.data_add(self.data, arg.get("bus-completer", 0), 8)
+        util.data_add(self.data, arg.get("target-id", 0), 8)
+
+        return qmp_cmd.send_cper(cper_guid.CPER_PCI_BUS, self.data)
-- 
2.52.0