[PATCH v4 4/5] powerpc/pseries/eeh: Implement RTAS-based EEH error injection

Narayana Murty N <[email protected]>
Newsgroups gmane.linux.ports.ppc.embedded
Message-ID <20260831065441.48654-5-nnmlinux__43371.0633007408$1788159363$gmane$org@linux.ibm.com>
Replace the legacy MMIO stub in pseries_eeh_err_inject() with a full
PAPR-compliant RTAS error injection path using the existing RTAS
work-area allocator.

The mutex is not a buffer lock; it serializes the firmware session
open/inject/close sequence as required by PAPR.  No global buffer
is allocated or used.

VFIO EEH error injection exposes a generic userspace ABI.  pSeries maps
the generic EEH error types to RTAS ibm,errinjct encodings via
pseries_eeh_type_to_rtas().  EEH_ERR_TYPE_32 and EEH_ERR_TYPE_64 are
unchanged; their values are defined in arch/powerpc/include/uapi/asm/eeh.h
and are not renumbered.

Tested with corresponding QEMU patches:
https://lore.kernel.org/all/[email protected]/

Signed-off-by: Narayana Murty N <[email protected]>
---
 arch/powerpc/platforms/pseries/eeh_pseries.c | 123 ++++++++++++++-----
 1 file changed, 95 insertions(+), 28 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index fafe0004e738..fcb8c560d813 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -25,6 +25,7 @@
 #include <linux/rbtree.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/crash_dump.h>
 
@@ -34,6 +35,7 @@
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
 #include <asm/rtas.h>
+#include <asm/rtas-work-area.h>
 
 /* RTAS tokens */
 static int ibm_set_eeh_option;
@@ -958,8 +960,6 @@ static int prepare_errinjct_buffer(void *buf, struct eeh_pe *pe,
 			return -EINVAL;
 
 		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 -EINVAL;
 		}
 
@@ -992,50 +992,117 @@ static int prepare_errinjct_buffer(void *buf, struct eeh_pe *pe,
 		break;
 
 	default:
-		pr_err("unsupported RTAS error injection type 0x%x\n", rtas_type);
+		pr_err("unsupported RTAS error injection type 0x%x\n",
+		       rtas_type);
 		return -EINVAL;
 	}
 
-	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-local mutex serializes the open/inject/close RTAS session */
+static DEFINE_MUTEX(pseries_errinjct_mutex);
+
 /**
  * pseries_eeh_err_inject - Inject specified error to the indicated PE
  * @pe: the indicated PE
- * @type: error type
- * @func: specific error type
- * @addr: address
- * @mask: address mask
- * The routine is called to inject specified error, which is
- * determined by @type and @func, to the indicated PE
+ * @type: generic EEH error type (EEH_ERR_TYPE_32 or EEH_ERR_TYPE_64)
+ * @func: specific error function
+ * @addr: address argument (type-dependent, may be zero)
+ * @mask: address mask (type-dependent, may be zero)
+ *
+ * Implements PAPR-compliant error injection using:
+ *   ibm,open-errinjct -> ibm,errinjct -> ibm,close-errinjct
+ *
+ * A short-lived RTAS work area is allocated per call; no global buffer
+ * is used.  pseries_errinjct_mutex serializes the open/inject/close
+ * session sequence.
+ *
+ * Return: 0 on success, negative errno on failure.
  */
 static int pseries_eeh_err_inject(struct eeh_pe *pe, int type, int func,
 				  unsigned long addr, unsigned long mask)
 {
-	struct	eeh_dev	*pdev;
+	struct rtas_work_area *area;
+	phys_addr_t area_phys;
+	u32 buf_phys;
+	void *buf;
+	int open_token, errinjct_token, close_token;
+	int session_token;
+	int rtas_type;
+	int close_rc;
+	int rc;
+
+	rc = validate_errinjct_args(pe, type, func, addr, mask);
+	if (rc)
+		return rc;
 
-	/* Check on PCI error type */
-	if (type != EEH_ERR_TYPE_32 && type != EEH_ERR_TYPE_64)
+	rtas_type = pseries_eeh_type_to_rtas(type);
+	if (rtas_type < 0)
 		return -EINVAL;
 
-	switch (func) {
-	case EEH_ERR_FUNC_LD_MEM_ADDR:
-	case EEH_ERR_FUNC_LD_MEM_DATA:
-	case EEH_ERR_FUNC_ST_MEM_ADDR:
-	case EEH_ERR_FUNC_ST_MEM_DATA:
-		/* injects a MMIO error for all pdev's belonging to PE */
-		pci_lock_rescan_remove();
-		list_for_each_entry(pdev, &pe->edevs, entry)
-			eeh_pe_inject_mmio_error(pdev->pdev);
-		pci_unlock_rescan_remove();
-		break;
-	default:
-		return -ERANGE;
+	open_token    = rtas_function_token(RTAS_FN_IBM_OPEN_ERRINJCT);
+	errinjct_token = rtas_function_token(RTAS_FN_IBM_ERRINJCT);
+	close_token   = rtas_function_token(RTAS_FN_IBM_CLOSE_ERRINJCT);
+
+	if (open_token    == RTAS_UNKNOWN_SERVICE ||
+	    errinjct_token == RTAS_UNKNOWN_SERVICE ||
+	    close_token   == RTAS_UNKNOWN_SERVICE)
+		return -ENODEV;
+
+	area = rtas_work_area_alloc(RTAS_ERRINJCT_BUF_SIZE);
+	buf  = rtas_work_area_raw_buf(area);
+	area_phys = rtas_work_area_phys(area);
+
+	if (WARN_ON_ONCE(upper_32_bits(area_phys))) {
+		rc = -ERANGE;
+		goto out_free_area;
 	}
 
-	return 0;
+	buf_phys = lower_32_bits(area_phys);
+
+	rc = prepare_errinjct_buffer(buf, pe, rtas_type, func, addr, mask);
+	if (rc)
+		goto out_free_area;
+
+	mutex_lock(&pseries_errinjct_mutex);
+
+	do {
+		rc = rtas_call(open_token, 0, 2, &session_token);
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		pr_err("ibm,open-errinjct failed: status=%d\n", rc);
+		rc = rtas_error_rc(rc);
+		goto out_unlock;
+	}
+
+	do {
+		rc = rtas_call(errinjct_token, 3, 1, NULL,
+			       rtas_type, session_token, buf_phys);
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		pr_err("ibm,errinjct failed: status=%d\n", rc);
+		rc = rtas_error_rc(rc);
+	}
+
+	do {
+		close_rc = rtas_call(close_token, 1, 1, NULL, session_token);
+	} while (rtas_busy_delay(close_rc));
+
+	if (close_rc) {
+		pr_warn("ibm,close-errinjct failed: status=%d\n", close_rc);
+		if (!rc)
+			rc = rtas_error_rc(close_rc);
+	}
+
+out_unlock:
+	mutex_unlock(&pseries_errinjct_mutex);
+
+out_free_area:
+	rtas_work_area_free(area);
+	return rc;
 }
 
 static struct eeh_ops pseries_eeh_ops = {
-- 
2.51.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.