[Skiboot] [PATCH 5/7] capp/phb4: Introduce PHB4 flag, PHB4_CAPP_DISABLE to disable CAPP

Vaibhav Jain vaibhav at linux.ibm.com
Sun Sep 16 00:39:24 AEST 2018


This patch introduces a PHB4 flag PHB4_CAPP_DISABLE and scaffolding
necessary to handle it during CRESET flow. The flag is set when CAPP
is request to switch to PCIe mode via call to phb4_set_capi_mode()
with mode OPAL_PHB_CAPI_MODE_PCIE. This starts the below sequence that
ultimately ends in newly introduced phb4_slot_sm_run_completed()

1. Set PHB4_CAPP_DISABLE to phb4->flags.

2. Start a CRESET on the phb slot. This also starts the opal pci reset
state machine.

3. Wait for slot state to be PHB4_SLOT_CRESET_WAIT_CQ.

4. Perform CAPP recovery as PHB is still fenced, by calling
do_capp_recovery_scoms().

5. Call newly introduced 'disable_capi_mode()' to disable CAPP.

6. Wait for slot reset to complete while it transitions to
PHB4_SLOT_FRESET and optionally to PHB4_SLOT_LINK_START.

7. Once slot reset is complete opal pci-core state machine will call
slot->ops.completed_sm_run().

8. For PHB4 this branches newly introduced 'phb4_slot_sm_run_completed()'.

9. Inside this function we mark the CAPP as disabled and un-register
the opal syncer phb4_host_sync_reset().

10. Optionally if the slot reset was unsuccessful disable
fast-reboot.

****************************
Notes:
****************************
a. Function 'disable_capi_mode()' performs various sanity tests on CAPP to
to determine if its ok to disable it and perform necessary xscoms
to disable it. However the current implementation proposed in this
patch is a skeleton one that just does sanity tests. A followup patch
will be proposed that implements the xscoms necessary to disable CAPP.

b. The sequence expects that Opal PCI reset state machine makes
forward progress hence needs someone to call slot->ops.run_sm(). This
can be either from phb4_host_sync_reset() or opal_pci_poll().

Signed-off-by: Vaibhav Jain <vaibhav at linux.ibm.com>
---
 hw/phb4.c      | 101 ++++++++++++++++++++++++++++++++++++++++++++++++-
 include/phb4.h |   1 +
 2 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/hw/phb4.c b/hw/phb4.c
index 615cda66..16a4a62a 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -2777,6 +2777,38 @@ static bool phb4_host_sync_reset(void *data)
 	return rc <= OPAL_SUCCESS;
 }
 
+/*
+ * Notification from the pci-core that a pci slot state machine completed.
+ * We use this callback to mark the CAPP disabled if we were waiting for it.
+ */
+static void phb4_slot_sm_run_completed(struct pci_slot *slot, uint64_t err)
+{
+	struct phb4 *p = phb_to_phb4(slot->phb);
+	struct proc_chip *chip = get_chip(p->chip_id);
+
+	/* Check if we are disabling the capp */
+	if (p->flags & PHB4_CAPP_DISABLE) {
+		/* Make sure we done stomp on some else's req to enable capp */
+		lock(&capi_lock);
+
+		/* Unset the flags so that we dont fall into a creset loop */
+		p->flags &= ~(PHB4_CAPP_DISABLE);
+		chip->capp_phb4_attached_mask &= ~(1 << p->index);
+
+		/* Remove the host sync notifier is we are done.*/
+		opal_del_host_sync_notifier_with_data(phb4_host_sync_reset,
+							      p);
+		if (err) {
+			/* Force a CEC ipl reboot */
+			disable_fast_reboot("CAPP: reset failed");
+			PHBERR(p, "CAPP: Unable to reset. Error=%lld\n", err);
+		} else {
+			PHBINF(p, "CAPP: reset complete\n");
+		}
+		unlock(&capi_lock);
+	}
+}
+
 static int64_t phb4_poll_link(struct pci_slot *slot)
 {
 	struct phb4 *p = phb_to_phb4(slot->phb);
@@ -3116,6 +3148,44 @@ static int do_capp_recovery_scoms(struct phb4 *p)
 	return rc;
 }
 
+/*
+ * Disable CAPI mode on a PHB. Must be done while PHB is fenced and
+ * not in recovery.
+ */
+static void disable_capi_mode(struct phb4 *p)
+{
+	struct proc_chip *chip = get_chip(p->chip_id);
+	uint64_t reg;
+	uint32_t offset = PHB4_CAPP_REG_OFFSET(p);
+
+	PHBINF(p, "CAPP: Deactivating\n");
+
+	/* Check if CAPP attached to the PHB and active */
+	if (!(chip->capp_phb4_attached_mask & (1 << p->index))) {
+		PHBERR(p, "CAPP: Not attached to this PHB!\n");
+		return;
+	}
+
+	xscom_read(p->chip_id, p->pe_xscom + XPEC_NEST_CAPP_CNTL, &reg);
+	if (!(reg & PPC_BIT(0))) {
+		/* Not in CAPI mode, no action required */
+		PHBDBG(p, "CAPP: Not enabled!\n");
+		return;
+	}
+
+	/* CAPP should already be out of recovery in this function */
+	xscom_read(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, &reg);
+	if (reg & PPC_BIT(0)) {
+		PHBERR(p, "CAPP: Cant disable while still in recovery!\n");
+		return;
+	}
+
+	PHBINF(p, "CAPP: Disabling CAPI mode\n");
+
+	/* Implement procedure to disable CAPP based on h/w sequence */
+}
+
+
 static int64_t phb4_creset(struct pci_slot *slot)
 {
 	struct phb4 *p = phb_to_phb4(slot->phb);
@@ -3176,6 +3246,9 @@ static int64_t phb4_creset(struct pci_slot *slot)
 			    (do_capp_recovery_scoms(p) != OPAL_SUCCESS))
 				goto error;
 
+			if (p->flags & PHB4_CAPP_DISABLE)
+				disable_capi_mode(p);
+
 			/* Clear errors in PFIR and NFIR */
 			xscom_write(p->chip_id, p->pci_stk_xscom + 0x1,
 				    ~p->pfir_cache);
@@ -3260,6 +3333,7 @@ static struct pci_slot *phb4_slot_create(struct phb *phb)
 	slot->ops.hreset		= phb4_hreset;
 	slot->ops.freset		= phb4_freset;
 	slot->ops.creset		= phb4_creset;
+	slot->ops.completed_sm_run      = phb4_slot_sm_run_completed;
 	slot->link_retries		= PHB4_LINK_LINK_RETRIES;
 
 	return slot;
@@ -4371,12 +4445,36 @@ static int64_t phb4_set_capi_mode(struct phb *phb, uint64_t mode,
 		break;
 
 	case OPAL_PHB_CAPI_MODE_SNOOP_OFF:
-	case OPAL_PHB_CAPI_MODE_PCIE: /* Not supported at the moment */
 		ret = !attached ? OPAL_SUCCESS : OPAL_UNSUPPORTED;
 		break;
 
+	case OPAL_PHB_CAPI_MODE_PCIE:
+		if (p->flags & PHB4_CAPP_DISABLE) {
+			/* We are in middle of a CAPP disable */
+			ret = OPAL_BUSY;
+
+		} else if (attached) {
+			p->flags |= PHB4_CAPP_DISABLE;
+			PHBINF(p, "CAPP: PCIE mode needs a cold-reset\n");
+			/* Kick off the pci state machine */
+			ret = phb4_creset(phb->slot);
+			ret = ret > 0 ? OPAL_BUSY : ret;
+
+		} else {
+			/* PHB already in PCI mode */
+			ret = OPAL_SUCCESS;
+		}
+		break;
+
 	case OPAL_PHB_CAPI_MODE_CAPI: /* Fall Through */
 	case OPAL_PHB_CAPI_MODE_DMA_TVT1:
+		/* Make sure that PHB is not disabling CAPP */
+		if (p->flags & PHB4_CAPP_DISABLE) {
+			PHBERR(p, "CAPP: Disable in progress\n");
+			ret = OPAL_BUSY;
+			break;
+		}
+
 		/* Check if ucode is available */
 		if (!capp_ucode_loaded(chip, p->index)) {
 			PHBERR(p, "CAPP: ucode not loaded\n");
@@ -4389,6 +4487,7 @@ static int64_t phb4_set_capi_mode(struct phb *phb, uint64_t mode,
 			PHBERR(p, "CAPP: recovery failed (%016llx)\n", reg);
 			ret = OPAL_HARDWARE;
 			break;
+
 		} else if ((reg & PPC_BIT(0)) && (!(reg & PPC_BIT(1)))) {
 			PHBDBG(p, "CAPP: recovery in progress\n");
 			ret = OPAL_BUSY;
diff --git a/include/phb4.h b/include/phb4.h
index d78bc317..050548be 100644
--- a/include/phb4.h
+++ b/include/phb4.h
@@ -164,6 +164,7 @@ struct phb4_err {
 #define PHB4_CFG_USE_ASB	0x00000002
 #define PHB4_CFG_BLOCKED	0x00000004
 #define PHB4_CAPP_RECOVERY	0x00000008
+#define PHB4_CAPP_DISABLE	0x00000010
 
 struct phb4 {
 	unsigned int		index;	    /* 0..5 index inside p9 */
-- 
2.17.1



More information about the Skiboot mailing list