[Skiboot] [PATCH v3] Add P9 DIO interrupt support

Lei YU mine260309 at gmail.com
Fri Jan 18 13:30:06 AEDT 2019


On P9 there are GPIO port 0, 1, 2 for GPIO interrupt, and DIO interrupt
is used to handle the interrupts.

Add support to the DIO interrupts:
1. Add dio_interrupt_register(chip, port, callback) to register the
   interrupt;
2. Add dio_interrupt_deregister(chip, port, callback) to deregister;
3. When interrupt on the port occurs, callback is invoked, and the
   interrupt status is cleared.

Signed-off-by: Lei YU <mine260309 at gmail.com>

---
v3: Add proc_chip* as callback argument for the handler to know which
    chip the interrupt occured on.
---
v2:
1. Put the callbacks into struct p9_dio in proc_chip
2. Register/deregister the DIO interrupt with chip and port, so that it
   works on all CPUs.
---
 core/init.c             |   4 ++
 hw/Makefile.inc         |   2 +-
 hw/dio-p9.c             | 146 ++++++++++++++++++++++++++++++++++++++++++++++++
 hw/psi.c                |   2 +
 include/chip.h          |   4 ++
 include/dio-p9.h        |  50 +++++++++++++++++
 include/xscom-p9-regs.h |   5 +-
 7 files changed, 211 insertions(+), 2 deletions(-)
 create mode 100644 hw/dio-p9.c
 create mode 100644 include/dio-p9.h

diff --git a/core/init.c b/core/init.c
index 262ac5f..0f79f5d 100644
--- a/core/init.c
+++ b/core/init.c
@@ -51,6 +51,7 @@
 #include <phys-map.h>
 #include <imc.h>
 #include <dts.h>
+#include <dio-p9.h>
 #include <sbe-p9.h>
 #include <debug_descriptor.h>
 #include <occ.h>
@@ -1081,6 +1082,9 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
 	 */
 	chiptod_init();
 
+	/* Initialize P9 DIO */
+	p9_dio_init();
+
 	/*
 	 * SBE uses TB value for scheduling timer. Hence init after
 	 * chiptod init
diff --git a/hw/Makefile.inc b/hw/Makefile.inc
index 005772a..e9fdb4c 100644
--- a/hw/Makefile.inc
+++ b/hw/Makefile.inc
@@ -9,7 +9,7 @@ HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o
 HW_OBJS += fake-nvram.o lpc-mbox.o npu2.o npu2-hw-procedures.o
 HW_OBJS += npu2-common.o phys-map.o sbe-p9.o capp.o occ-sensor.o vas.o
 HW_OBJS += npu2-common.o npu2-opencapi.o phys-map.o sbe-p9.o capp.o occ-sensor.o
-HW_OBJS += vas.o sbe-p8.o
+HW_OBJS += vas.o sbe-p8.o dio-p9.o
 HW=hw/built-in.a
 
 include $(SRC)/hw/fsp/Makefile.inc
diff --git a/hw/dio-p9.c b/hw/dio-p9.c
new file mode 100644
index 0000000..e2d40ac
--- /dev/null
+++ b/hw/dio-p9.c
@@ -0,0 +1,146 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#define pr_fmt(fmt) "DIO: " fmt
+
+#include <chip.h>
+#include <dio-p9.h>
+#include <opal.h>
+#include <xscom.h>
+#include <xscom-p9-regs.h>
+
+void p9_dio_init(void)
+{
+	struct dt_node *xn;
+	struct proc_chip *chip;
+	struct p9_dio *dio;
+
+	if (proc_gen < proc_gen_p9)
+		return;
+
+	dt_for_each_compatible(dt_root, xn, "ibm,xscom") {
+		dio = zalloc(sizeof(struct p9_dio));
+		assert(dio);
+		chip = get_chip(dt_get_chip_id(xn));
+		assert(chip);
+		chip->dio = dio;
+	}
+}
+
+int dio_interrupt_register(struct proc_chip *chip,
+		int port, dio_interrupt_callback callback)
+{
+	u64 val;
+	int rc;
+
+	assert(chip);
+	assert(chip->dio);
+
+	if (port < 0 || port >= NUM_OF_P9_DIO_PORTS)
+		return OPAL_PARAMETER;
+
+	if (chip->dio->callbacks[port]) /* This port already has a callback */
+		return OPAL_PARAMETER;
+
+	rc = xscom_read(chip->id, P9_GPIO_INTERRUPT_ENABLE, &val);
+	if (rc != OPAL_SUCCESS) {
+		prlog(PR_ERR, "XSCOM error %d reading reg 0x%llx\n",
+				rc, P9_GPIO_INTERRUPT_ENABLE);
+		return OPAL_HARDWARE;
+	}
+
+	val |= PPC_BIT(port);
+	rc = xscom_write(chip->id, P9_GPIO_INTERRUPT_ENABLE, val);
+	if (rc != OPAL_SUCCESS) {
+		prlog(PR_ERR, "XSCOM error %d writing reg 0x%llx\n",
+				rc, P9_GPIO_INTERRUPT_ENABLE);
+		return OPAL_HARDWARE;
+	}
+
+	chip->dio->callbacks[port] = callback;
+
+	return OPAL_SUCCESS;
+}
+
+int dio_interrupt_deregister(struct proc_chip* chip,
+		int port, dio_interrupt_callback callback)
+{
+	u64 val;
+	int rc;
+
+	assert(chip);
+	assert(chip->dio);
+
+	if (port < 0 || port >= NUM_OF_P9_DIO_PORTS)
+		return OPAL_PARAMETER;
+
+	if (chip->dio->callbacks[port] != callback)
+		return OPAL_PARAMETER;
+
+	rc = xscom_read(chip->id, P9_GPIO_INTERRUPT_ENABLE, &val);
+	if (rc != OPAL_SUCCESS) {
+		prlog(PR_ERR, "XSCOM error %d reading reg 0x%llx\n",
+				rc, P9_GPIO_INTERRUPT_ENABLE);
+		return OPAL_HARDWARE;
+	}
+
+	val &= ~PPC_BIT(port);
+	rc = xscom_write(chip->id, P9_GPIO_INTERRUPT_ENABLE, val);
+	if (rc != OPAL_SUCCESS) {
+		prlog(PR_ERR, "XSCOM error %d writing reg 0x%llx\n",
+				rc, P9_GPIO_INTERRUPT_ENABLE);
+		return OPAL_HARDWARE;
+	}
+
+	chip->dio->callbacks[port] = NULL;
+
+	return OPAL_SUCCESS;
+}
+
+void dio_interrupt_handler(uint32_t chip_id)
+{
+	struct proc_chip *chip;
+	u64 val;
+	int rc;
+	int i;
+
+	chip = get_chip(chip_id);
+	if (chip == NULL || chip->dio == NULL)
+		return;
+
+	rc = xscom_read(chip->id, P9_GPIO_INTERRUPT_STATUS, &val);
+	if (rc != OPAL_SUCCESS) {
+		prlog(PR_ERR, "XSCOM error %d reading reg 0x%llx\n",
+				rc, P9_GPIO_INTERRUPT_STATUS);
+		return;
+	}
+
+	for (i = 0; i < NUM_OF_P9_DIO_PORTS; ++i) {
+		if (val & PPC_BIT(i)) {
+			if (chip->dio->callbacks[i])
+				chip->dio->callbacks[i](chip);
+			else
+				prlog(PR_ERR,
+					"DIO interrupt triggerd on chip 0x%x"
+					" port %d but no handler\n",
+					chip->id, i);
+			/* Write 1 to clear the interrupt status */
+			xscom_write(chip->id, P9_GPIO_INTERRUPT_CONDITION,
+					val & PPC_BIT(i));
+		}
+	}
+}
diff --git a/hw/psi.c b/hw/psi.c
index cbdbeaa..719a0aa 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -24,6 +24,7 @@
 #include <gx.h>
 #include <interrupts.h>
 #include <cpu.h>
+#include <dio-p9.h>
 #include <trace.h>
 #include <xscom.h>
 #include <chip.h>
@@ -604,6 +605,7 @@ static void psihb_p9_interrupt(struct irq_source *is, uint32_t isn)
 		break;
 	case P9_PSI_IRQ_DIO:
 		printf("PSI: DIO irq received\n");
+		dio_interrupt_handler(psi->chip_id);
 		break;
 	case P9_PSI_IRQ_PSU:
 		p9_sbe_interrupt(psi->chip_id);
diff --git a/include/chip.h b/include/chip.h
index 2fb8126..eaf7478 100644
--- a/include/chip.h
+++ b/include/chip.h
@@ -114,6 +114,7 @@ struct xive;
 struct lpcm;
 struct vas;
 struct p9_sbe;
+struct p9_dio;
 
 /* Chip type */
 enum proc_chip_type {
@@ -224,6 +225,9 @@ struct proc_chip {
 
 	/* Used by hw/sbe-p9.c */
 	struct p9_sbe		*sbe;
+
+	/* Used by hw/dio-p9.c */
+	struct p9_dio		*dio;
 };
 
 extern uint32_t pir_to_chip_id(uint32_t pir);
diff --git a/include/dio-p9.h b/include/dio-p9.h
new file mode 100644
index 0000000..65aed2d
--- /dev/null
+++ b/include/dio-p9.h
@@ -0,0 +1,50 @@
+
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DIO_H
+#define __DIO_H
+
+struct proc_chip;
+
+/* Initialize the P9 DIO */
+extern void p9_dio_init(void);
+
+/* The function typedef for dio interrupt callback */
+typedef void (*dio_interrupt_callback)(struct proc_chip *chip);
+
+/* Register dio interrupt on GPIO port.
+ * This effectively enables the DIO interrupt on the GPIO port,
+ * and callback will be called when the interrupt is triggered */
+extern int dio_interrupt_register(struct proc_chip *chip,
+		int port, dio_interrupt_callback c);
+
+/* Deregister dio interrupt on GPIO port.
+ * This effectively disables the DIO interrupt on the GPIO port. */
+extern int dio_interrupt_deregister(struct proc_chip *chip,
+		int port, dio_interrupt_callback c);
+
+/* The function to be called when DIO interrupt is triggered */
+extern void dio_interrupt_handler(uint32_t chip_id);
+
+
+#define NUM_OF_P9_DIO_PORTS	3 /* P9 has GPIO port 0~2 for interrupts */
+
+struct p9_dio {
+	dio_interrupt_callback callbacks[NUM_OF_P9_DIO_PORTS];
+};
+
+#endif	/* __DIO_H */
diff --git a/include/xscom-p9-regs.h b/include/xscom-p9-regs.h
index 42dd426..d47c222 100644
--- a/include/xscom-p9-regs.h
+++ b/include/xscom-p9-regs.h
@@ -18,8 +18,11 @@
 #define P9X_EX_NCU_DARN_BAR			0x11011
 #define  P9X_EX_NCU_DARN_BAR_EN			PPC_BIT(0)
 
-#define P9_GPIO_DATA_OUT_ENABLE			0x00000000000B0054ull
 #define P9_GPIO_DATA_OUT			0x00000000000B0051ull
+#define P9_GPIO_DATA_OUT_ENABLE			0x00000000000B0054ull
+#define P9_GPIO_INTERRUPT_STATUS		0x00000000000B0057ull
+#define P9_GPIO_INTERRUPT_ENABLE		0x00000000000B005Dull
+#define P9_GPIO_INTERRUPT_CONDITION		0x00000000000B005Eull
 
 /* xscom address for SCOM Control and data Register */
 /* bits 54:60 of SCOM SPRC register is used for core specific SPR selection. */
-- 
2.7.4



More information about the Skiboot mailing list