diff mbox series

[2/3] SBE: Use the Ultravisor to interact with the SBE

Message ID 20200328010806.20621-3-bauerman@linux.ibm.com
State New
Headers show
Series Ultravisor SBE chipops | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch fail Failed to apply to any branch
snowpatch_ozlabs/apply_patch warning Failed to apply on branch master (d703ad5b8ea93f2bcd98ca2642dcd3c66da82c91)

Commit Message

Thiago Jung Bauermann March 28, 2020, 1:08 a.m. UTC
When an Ultravisor is present, access to XCOMs used to interact with the
SBE are denied. To deal with that, the Ultravisor offers an
UV_SEND_SBE_COMMAND ultracall which Skiboot can use to request some
SBE operations to be performed by the Ultravisor on its behalf.

We use it to set up the timer, to read the SBE doorbell register when
receiving an interrupt from the SBE and for starting an MPIPL.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.ibm.com>
---
 hw/sbe-p9.c          | 75 +++++++++++++++++++++++++++++++++++++++-----
 include/ultravisor.h | 20 ++++++++++++
 2 files changed, 88 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/hw/sbe-p9.c b/hw/sbe-p9.c
index 5ff44d545..bbe2f46d9 100644
--- a/hw/sbe-p9.c
+++ b/hw/sbe-p9.c
@@ -354,8 +354,17 @@  static void p9_sbe_process_queue(struct p9_sbe *sbe)
 
 	while (!list_empty(&sbe->msg_list)) {
 		msg = list_top(&sbe->msg_list, struct p9_sbe_msg, link);
+
 		/* Send message */
-		rc = p9_sbe_msg_send(sbe, msg);
+		if (uv_present) {
+			/* This is the only message that we ever send. */
+			assert(msg == timer_ctrl_msg);
+
+			rc = uv_send_sbe_command(sbe->chip_id, SBE_CHIPOP_TIMER,
+						 msg->reg[1], NULL);
+		} else
+			rc = p9_sbe_msg_send(sbe, msg);
+
 		if (rc == OPAL_SUCCESS)
 			return;
 
@@ -647,6 +656,36 @@  again:
 	}
 }
 
+/*
+ * Use the Ultravisor to learn what caused an SBE interrupt, and act
+ * accordingly.
+ *
+ * WARNING: This will drop sbe->lock
+ */
+static void p9_uv_handle_sbe_interrupt(struct p9_sbe *sbe)
+{
+	uint64_t doorbell;
+	int rc;
+
+	do {
+		rc = uv_send_sbe_command(sbe->chip_id,
+					 SBE_CHIPOP_HANDLE_INTERRUPT, 0,
+					 &doorbell);
+
+		if (doorbell & SBE_HOST_RESET)
+			p9_sbe_after_reset(sbe);
+
+		if (doorbell & SBE_HOST_MSG_READ)
+			p9_sbe_send_complete(sbe);
+
+		if (doorbell & SBE_HOST_PASSTHROUGH)
+			prd_sbe_passthrough(sbe->chip_id);
+
+		if (doorbell & SBE_HOST_TIMER_EXPIRY)
+			p9_sbe_timer_response(sbe);
+	} while (rc == 0 && doorbell != 0);
+}
+
 void p9_sbe_interrupt(uint32_t chip_id)
 {
 	struct proc_chip *chip;
@@ -658,8 +697,14 @@  void p9_sbe_interrupt(uint32_t chip_id)
 
 	sbe = chip->sbe;
 	lock(&sbe->lock);
-	__p9_sbe_interrupt(sbe);
+
+	if (uv_present)
+		p9_uv_handle_sbe_interrupt(sbe);
+	else
+		__p9_sbe_interrupt(sbe);
+
 	p9_sbe_process_queue(sbe);
+
 	unlock(&sbe->lock);
 }
 
@@ -708,7 +753,11 @@  static void p9_sbe_timeout_poll_one(struct p9_sbe *sbe)
 	 * possible that SBE has responded, but OPAL didn't act on that.
 	 * Hence check for SBE response.
 	 */
-	__p9_sbe_interrupt(sbe);
+	if (uv_present)
+		p9_uv_handle_sbe_interrupt(sbe);
+	else
+		__p9_sbe_interrupt(sbe);
+
 	p9_sbe_timer_poll(sbe);
 
 	if (list_empty(&sbe->msg_list))
@@ -948,6 +997,20 @@  void p9_sbe_init(void)
 	opal_add_poller(p9_sbe_timeout_poll, NULL);
 }
 
+static int p9_sbe_start_mpipl(u64 chip_id)
+{
+	int rc;
+
+	if (uv_present)
+		rc = uv_send_sbe_command(chip_id, SBE_CHIPOP_START_MPIPL,
+					 0, NULL);
+	else
+		rc = xscom_write(chip_id, SBE_CONTROL_REG_RW,
+				 SBE_CONTROL_REG_S0);
+
+	return rc;
+}
+
 /* Terminate and initiate MPIPL */
 void p9_sbe_terminate(void)
 {
@@ -980,8 +1043,7 @@  void p9_sbe_terminate(void)
 			continue;
 		}
 
-		rc = xscom_write(chip->id,
-				 SBE_CONTROL_REG_RW, SBE_CONTROL_REG_S0);
+		rc = p9_sbe_start_mpipl(chip->id);
 		/* Initiate normal reboot */
 		if (rc) {
 			prlog(PR_ERR, "Failed to write S0 interrupt [chip id = %x]\n",
@@ -996,8 +1058,7 @@  void p9_sbe_terminate(void)
 		return;
 	}
 
-	rc = xscom_write(primary_chip,
-			 SBE_CONTROL_REG_RW, SBE_CONTROL_REG_S0);
+	rc = p9_sbe_start_mpipl(primary_chip);
 	if (rc) {
 		prlog(PR_ERR, "Failed to write S0 interrupt [chip id = %x]\n",
 		      primary_chip);
diff --git a/include/ultravisor.h b/include/ultravisor.h
index 347b085d7..eb855687c 100644
--- a/include/ultravisor.h
+++ b/include/ultravisor.h
@@ -14,8 +14,15 @@ 
 #define UCALL_BUFSIZE 4
 #define UV_READ_SCOM  0xF114
 #define UV_WRITE_SCOM 0xF118
+#define UV_SEND_SBE_COMMAND 0xF150
 #define UV_FDT_MAX_SIZE		0x100000
 
+enum sbe_chipop_ops {
+	SBE_CHIPOP_TIMER,
+	SBE_CHIPOP_HANDLE_INTERRUPT,
+	SBE_CHIPOP_START_MPIPL,
+};
+
 extern long ucall(unsigned long opcode, unsigned long *retbuf, ...);
 extern int start_uv(uint64_t entry, void *fdt);
 extern bool uv_present;
@@ -41,4 +48,17 @@  static inline int uv_xscom_write(u64 partid, u64 pcb_addr, u64 val)
 	return ucall(UV_WRITE_SCOM, retbuf, partid, pcb_addr, val);
 }
 
+static inline int uv_send_sbe_command(u64 chip_id, enum sbe_chipop_ops opcode,
+				      u64 input, u64 *output)
+{
+	unsigned long retbuf[UCALL_BUFSIZE];
+	int rc;
+
+	rc = ucall(UV_SEND_SBE_COMMAND, retbuf, chip_id, opcode, input);
+	if (output)
+		*output = retbuf[0];
+
+	return rc;
+}
+
 #endif /* __ULTRAVISOR_H */