From: Narayana Murty N <nnmlinux@linux.ibm.com>
To: mahesh@linux.ibm.com, maddy@linux.ibm.com, mpe@ellerman.id.au,
christophe.leroy@csgroup.eu, gregkh@linuxfoundation.org,
oohall@gmail.com, npiggin@gmail.com
Cc: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
tyreld@linux.ibm.com, vaibhav@linux.ibm.com, sbhat@linux.ibm.com,
ganeshgr@linux.ibm.com, sourabhjain@linux.ibm.com,
haren@linux.ibm.com, nnmlinux@linux.ibm.com, thuth@redhat.com
Subject: [PATCH v3 3/5] powerpc/pseries/eeh: Add RTAS error validation helpers
Date: Tue, 21 Jul 2026 09:08:03 +0530 [thread overview]
Message-ID: <20260721033815.5300-4-nnmlinux@linux.ibm.com> (raw)
In-Reply-To: <20260721033815.5300-1-nnmlinux@linux.ibm.com>
Add validation helpers and buffer-preparation infrastructure used by
the RTAS-based EEH error injection implementation.
Changes relative to the original submission:
- pr_fmt unconditionally defined at the top of the file, not wrapped
in an #ifndef guard.
- RTAS error-type constants (RTAS_ERR_TYPE_*) are defined as file-local
macros in eeh_pseries.c, not in the UAPI header. They are internal
PAPR firmware type codes, not generic EEH ABI values.
- validate_corrupted_page() drops the unused 'pe' parameter entirely
(no __maybe_unused). The mask value is silently accepted since it
is not meaningful for this error type.
- validate_ioa_bus_error() is removed; callers invoke
validate_addr_mask_in_pe() directly.
- validate_err_type() and validate_special_event() and
validate_corrupted_page() are marked static inline.
- prepare_errinjct_buffer() takes an explicit 'void *buf' pointer
(kernel virtual address) instead of accessing rtas_errinjct_buf
directly, making it easier to test and keeping the global out of
the helper.
- kernel-doc added for prepare_errinjct_buffer() including a Locking:
line stating the caller must hold rtas_errinjct_mutex.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202512101130.EYUo0oZx-lkp@intel.com/
Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
---
arch/powerpc/include/uapi/asm/eeh.h | 24 +-
arch/powerpc/platforms/pseries/eeh_pseries.c | 250 +++++++++++++++++++
2 files changed, 271 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/uapi/asm/eeh.h b/arch/powerpc/include/uapi/asm/eeh.h
index 3b5c47ff3fc4..2680b22f8917 100644
--- a/arch/powerpc/include/uapi/asm/eeh.h
+++ b/arch/powerpc/include/uapi/asm/eeh.h
@@ -15,9 +15,27 @@
#define EEH_PE_STATE_STOPPED_DMA 4 /* Stopped DMA only */
#define EEH_PE_STATE_UNAVAIL 5 /* Unavailable */
-/* EEH error types and functions */
-#define EEH_ERR_TYPE_32 0 /* 32-bits error */
-#define EEH_ERR_TYPE_64 1 /* 64-bits error */
+/*
+ * EEH error types.
+ *
+ * EEH_ERR_TYPE_32 and EEH_ERR_TYPE_64 are the original ABI values and must
+ * not be renumbered. The additional types below are generic identifiers for
+ * error-injection types supported by pSeries RTAS. Platform backends may
+ * return -EOPNOTSUPP for valid generic types that are not supported by their
+ * firmware.
+ */
+#define EEH_ERR_TYPE_32 0 /* 32-bits error */
+#define EEH_ERR_TYPE_64 1 /* 64-bits error */
+#define EEH_ERR_TYPE_RECOVERED_SPECIAL_EVENT 0x03
+#define EEH_ERR_TYPE_CORRUPTED_PAGE 0x04
+#define EEH_ERR_TYPE_CORRUPTED_DCACHE_START 0x09
+#define EEH_ERR_TYPE_CORRUPTED_DCACHE_END 0x0a
+#define EEH_ERR_TYPE_CORRUPTED_ICACHE_START 0x0b
+#define EEH_ERR_TYPE_CORRUPTED_ICACHE_END 0x0c
+#define EEH_ERR_TYPE_CORRUPTED_TLB_START 0x0d
+#define EEH_ERR_TYPE_CORRUPTED_TLB_END 0x0e
+
+/* EEH error functions */
#define EEH_ERR_FUNC_MIN 0
#define EEH_ERR_FUNC_LD_MEM_ADDR 0 /* Memory load */
#define EEH_ERR_FUNC_LD_MEM_DATA 1
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index b12ef382fec7..25aad86c696d 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+#define pr_fmt(fmt) "EEH: " fmt
/*
* The file intends to implement the platform dependent EEH operations on pseries.
* Actually, the pseries platform is built based on RTAS heavily. That means the
@@ -31,8 +32,27 @@
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/ppc-pci.h>
+#include <linux/mutex.h>
#include <asm/rtas.h>
+/*
+ * PAPR RTAS firmware error-injection type codes.
+ *
+ * These are internal firmware encodings used by ibm,errinjct. They are
+ * NOT generic EEH ABI values. Only the types actually handled by
+ * prepare_errinjct_buffer() are defined here.
+ */
+#define RTAS_ERR_TYPE_RECOVERED_SPECIAL_EVENT 0x03
+#define RTAS_ERR_TYPE_CORRUPTED_PAGE 0x04
+#define RTAS_ERR_TYPE_IOA_BUS_ERROR 0x07
+#define RTAS_ERR_TYPE_CORRUPTED_DCACHE_START 0x09
+#define RTAS_ERR_TYPE_CORRUPTED_DCACHE_END 0x0a
+#define RTAS_ERR_TYPE_CORRUPTED_ICACHE_START 0x0b
+#define RTAS_ERR_TYPE_CORRUPTED_ICACHE_END 0x0c
+#define RTAS_ERR_TYPE_CORRUPTED_TLB_START 0x0d
+#define RTAS_ERR_TYPE_CORRUPTED_TLB_END 0x0e
+#define RTAS_ERR_TYPE_IOA_BUS_ERROR_64 0x0f
+
/* RTAS tokens */
static int ibm_set_eeh_option;
static int ibm_set_slot_reset;
@@ -786,6 +806,236 @@ static int pseries_notify_resume(struct eeh_dev *edev)
}
#endif
+/**
+ * validate_addr_mask_in_pe() - Validate that addr+mask fall within PE BARs
+ * @pe: EEH PE containing one or more PCI devices
+ * @addr: Address to validate
+ * @mask: Address mask to validate
+ *
+ * Checks that @addr is mapped into a BAR/MMIO region of any device
+ * belonging to the PE. If @mask is non-zero, ensures it is consistent
+ * with @addr.
+ *
+ * Return: 0 if valid, RTAS_INVALID_PARAMETER on failure.
+ */
+static int validate_addr_mask_in_pe(struct eeh_pe *pe, unsigned long addr,
+ unsigned long mask)
+{
+ struct eeh_dev *edev, *tmp;
+ struct pci_dev *pdev;
+ int bar;
+ resource_size_t bar_start, bar_len;
+ bool valid = false;
+
+ /* nothing to validate */
+ if (addr == 0 && mask == 0)
+ return 0;
+
+ eeh_pe_for_each_dev(pe, edev, tmp) {
+ pdev = eeh_dev_to_pci_dev(edev);
+ if (!pdev)
+ continue;
+
+ for (bar = 0; bar < PCI_NUM_RESOURCES; bar++) {
+ bar_start = pci_resource_start(pdev, bar);
+ bar_len = pci_resource_len(pdev, bar);
+
+ if (!bar_len)
+ continue;
+
+ if (addr >= bar_start && addr < (bar_start + bar_len)) {
+ if ((addr & mask) != addr) {
+ pr_err("Mask 0x%lx invalid for addr 0x%lx in BAR[%d] range 0x%llx-0x%llx\n",
+ mask, addr, bar,
+ (unsigned long long)bar_start,
+ (unsigned long long)(bar_start + bar_len));
+ return RTAS_INVALID_PARAMETER;
+ }
+ pr_debug("addr=0x%lx mask=0x%lx validated in BAR[%d] of %s\n",
+ addr, mask, bar, pci_name(pdev));
+ valid = true;
+ }
+ }
+ }
+
+ if (!valid) {
+ pr_err("addr=0x%lx not within any BAR of any device in PE\n",
+ addr);
+ return RTAS_INVALID_PARAMETER;
+ }
+
+ return 0;
+}
+
+/**
+ * validate_special_event() - Validate parameters for special-event injection
+ * @addr: Address parameter (must be zero for this type)
+ * @mask: Mask parameter (must be zero for this type)
+ *
+ * Return: 0 if valid, RTAS_INVALID_PARAMETER otherwise.
+ */
+static inline int validate_special_event(unsigned long addr, unsigned long mask)
+{
+ if (addr || mask) {
+ pr_err("special-event injection must not specify addr/mask\n");
+ return RTAS_INVALID_PARAMETER;
+ }
+ return 0;
+}
+
+/**
+ * validate_corrupted_page() - Validate parameters for corrupted-page injection
+ * @addr: Physical page address (required, must be non-zero)
+ *
+ * The mask value is not meaningful for this error type and is ignored.
+ *
+ * Return: 0 if valid, RTAS_INVALID_PARAMETER otherwise.
+ */
+static inline int validate_corrupted_page(unsigned long addr)
+{
+ if (!addr) {
+ pr_err("corrupted-page injection requires non-zero addr\n");
+ return RTAS_INVALID_PARAMETER;
+ }
+ return 0;
+}
+
+/**
+ * pseries_eeh_type_to_rtas() - Map a generic EEH error type to its RTAS encoding.
+ * @type: Generic EEH error type (EEH_ERR_TYPE_*)
+ *
+ * Translates a userspace-visible generic EEH error type to the corresponding
+ * PAPR RTAS firmware type code. Every supported value appears as an explicit
+ * case; coincidental equality between generic EEH and RTAS values is not relied
+ * upon.
+ *
+ * Return: RTAS_ERR_TYPE_* value on success, -EINVAL for unsupported types.
+ */
+static int pseries_eeh_type_to_rtas(int type)
+{
+ switch (type) {
+ case EEH_ERR_TYPE_32:
+ return RTAS_ERR_TYPE_IOA_BUS_ERROR;
+ case EEH_ERR_TYPE_64:
+ return RTAS_ERR_TYPE_IOA_BUS_ERROR_64;
+ case EEH_ERR_TYPE_RECOVERED_SPECIAL_EVENT:
+ return RTAS_ERR_TYPE_RECOVERED_SPECIAL_EVENT;
+ case EEH_ERR_TYPE_CORRUPTED_PAGE:
+ return RTAS_ERR_TYPE_CORRUPTED_PAGE;
+ case EEH_ERR_TYPE_CORRUPTED_DCACHE_START:
+ return RTAS_ERR_TYPE_CORRUPTED_DCACHE_START;
+ case EEH_ERR_TYPE_CORRUPTED_DCACHE_END:
+ return RTAS_ERR_TYPE_CORRUPTED_DCACHE_END;
+ case EEH_ERR_TYPE_CORRUPTED_ICACHE_START:
+ return RTAS_ERR_TYPE_CORRUPTED_ICACHE_START;
+ case EEH_ERR_TYPE_CORRUPTED_ICACHE_END:
+ return RTAS_ERR_TYPE_CORRUPTED_ICACHE_END;
+ case EEH_ERR_TYPE_CORRUPTED_TLB_START:
+ return RTAS_ERR_TYPE_CORRUPTED_TLB_START;
+ case EEH_ERR_TYPE_CORRUPTED_TLB_END:
+ return RTAS_ERR_TYPE_CORRUPTED_TLB_END;
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * prepare_errinjct_buffer() - Build ibm,errinjct work buffer
+ * @buf: RTAS error-injection work buffer (kernel virtual address)
+ * @pe: EEH PE associated with the injection target
+ * @rtas_type: PAPR firmware error-injection type after generic EEH-to-RTAS
+ * translation (RTAS_ERR_TYPE_*)
+ * @func: Error function selector
+ * @addr: Target address, if applicable
+ * @mask: Address mask, if applicable
+ *
+ * Zeroes @buf and populates it according to the PAPR layout for @rtas_type.
+ * Performs inline parameter validation for each error type.
+ *
+ * Locking: Caller must hold rtas_errinjct_mutex.
+ *
+ * Return: 0 on success, RTAS_INVALID_PARAMETER on invalid input.
+ */
+static int prepare_errinjct_buffer(void *buf, struct eeh_pe *pe,
+ int rtas_type, int func,
+ unsigned long addr, unsigned long mask)
+{
+ __be64 *buf64 = (__be64 *)buf;
+ __be32 *buf32 = (__be32 *)buf;
+
+ memset(buf, 0, RTAS_ERRINJCT_BUF_SIZE);
+
+ switch (rtas_type) {
+ case RTAS_ERR_TYPE_RECOVERED_SPECIAL_EVENT:
+ /* func: 1 = non-persistent, 2 = persistent */
+ if (func < 1 || func > 2)
+ return RTAS_INVALID_PARAMETER;
+ if (validate_special_event(addr, mask))
+ return RTAS_INVALID_PARAMETER;
+ buf32[0] = cpu_to_be32(func);
+ break;
+
+ case RTAS_ERR_TYPE_CORRUPTED_PAGE:
+ if (validate_corrupted_page(addr))
+ return RTAS_INVALID_PARAMETER;
+ buf32[0] = cpu_to_be32(upper_32_bits(addr));
+ buf32[1] = cpu_to_be32(lower_32_bits(addr));
+ break;
+
+ case RTAS_ERR_TYPE_IOA_BUS_ERROR:
+ if (func < EEH_ERR_FUNC_LD_MEM_ADDR || func > EEH_ERR_FUNC_MAX)
+ return RTAS_INVALID_PARAMETER;
+ if (upper_32_bits(addr) || upper_32_bits(mask)) {
+ pr_err("32-bit IOA injection cannot encode addr=%#lx mask=%#lx\n",
+ addr, mask);
+ return RTAS_INVALID_PARAMETER;
+ }
+ if (validate_addr_mask_in_pe(pe, addr, mask))
+ return RTAS_INVALID_PARAMETER;
+ buf32[0] = cpu_to_be32((u32)addr);
+ buf32[1] = cpu_to_be32((u32)mask);
+ buf32[2] = cpu_to_be32(pe->addr);
+ buf32[3] = cpu_to_be32(BUID_HI(pe->phb->buid));
+ buf32[4] = cpu_to_be32(BUID_LO(pe->phb->buid));
+ buf32[5] = cpu_to_be32(func);
+ break;
+
+ case RTAS_ERR_TYPE_IOA_BUS_ERROR_64:
+ if (func < EEH_ERR_FUNC_MIN || func > EEH_ERR_FUNC_MAX)
+ return RTAS_INVALID_PARAMETER;
+ if (validate_addr_mask_in_pe(pe, addr, mask))
+ return RTAS_INVALID_PARAMETER;
+ buf64[0] = cpu_to_be64(addr);
+ buf64[1] = cpu_to_be64(mask);
+ buf32[4] = cpu_to_be32(pe->addr);
+ buf32[5] = cpu_to_be32(BUID_HI(pe->phb->buid));
+ buf32[6] = cpu_to_be32(BUID_LO(pe->phb->buid));
+ buf32[7] = cpu_to_be32(func);
+ break;
+
+ case RTAS_ERR_TYPE_CORRUPTED_DCACHE_START:
+ case RTAS_ERR_TYPE_CORRUPTED_DCACHE_END:
+ case RTAS_ERR_TYPE_CORRUPTED_ICACHE_START:
+ case RTAS_ERR_TYPE_CORRUPTED_ICACHE_END:
+ buf32[0] = cpu_to_be32(lower_32_bits(addr));
+ buf32[1] = cpu_to_be32(lower_32_bits(mask));
+ break;
+
+ case RTAS_ERR_TYPE_CORRUPTED_TLB_START:
+ case RTAS_ERR_TYPE_CORRUPTED_TLB_END:
+ buf32[0] = cpu_to_be32(lower_32_bits(addr));
+ break;
+
+ default:
+ pr_err("unsupported RTAS error injection type 0x%x\n", rtas_type);
+ return RTAS_INVALID_PARAMETER;
+ }
+
+ pr_debug("errinjct buffer ready: rtas_type=0x%x func=%d addr=0x%lx mask=0x%lx\n",
+ rtas_type, func, addr, mask);
+ return 0;
+}
+
/**
* pseries_eeh_err_inject - Inject specified error to the indicated PE
* @pe: the indicated PE
--
2.54.0
next prev parent reply other threads:[~2026-07-21 3:39 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-21 3:38 [PATCH v3 0/5] powerpc/eeh: Add RTAS-based error injection support on pSeries Narayana Murty N
2026-07-21 3:38 ` [PATCH v3 1/5] powerpc/rtas: Handle ibm,open-errinjct return format Narayana Murty N
2026-07-21 3:38 ` [PATCH v3 2/5] powerpc/rtas: Allocate ibm,errinjct buffer below RTAS limit Narayana Murty N
2026-07-21 3:38 ` Narayana Murty N [this message]
2026-07-21 3:38 ` [PATCH v3 4/5] powerpc/pseries/eeh: Implement RTAS-based EEH error injection Narayana Murty N
2026-07-21 3:38 ` [PATCH v3 5/5] powerpc/powernv/eeh: Map VFIO EEH error injection to OPAL Narayana Murty N
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260721033815.5300-4-nnmlinux@linux.ibm.com \
--to=nnmlinux@linux.ibm.com \
--cc=christophe.leroy@csgroup.eu \
--cc=ganeshgr@linux.ibm.com \
--cc=gregkh@linuxfoundation.org \
--cc=haren@linux.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=maddy@linux.ibm.com \
--cc=mahesh@linux.ibm.com \
--cc=mpe@ellerman.id.au \
--cc=npiggin@gmail.com \
--cc=oohall@gmail.com \
--cc=sbhat@linux.ibm.com \
--cc=sourabhjain@linux.ibm.com \
--cc=thuth@redhat.com \
--cc=tyreld@linux.ibm.com \
--cc=vaibhav@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.