Message ID | 20190108095902.24718-7-vaibhav@linux.ibm.com |
---|---|
State | Superseded |
Headers | show |
Series | Enable fast-reboot support for CAPI-2 | expand |
Context | Check | Description |
---|---|---|
snowpatch_ozlabs/apply_patch | success | master/apply_patch Successfully applied |
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot | success | Test snowpatch/job/snowpatch-skiboot on branch master |
Le 08/01/2019 à 10:59, Vaibhav Jain a écrit : > 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(). > > Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> > Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com> > --- > Change-log > > v3: Use 'struct capp *' from struct phb4 instead of struct phb. > Minor typo fixed. [ Andrew ] > > v2: Removed the usage of global mutex 'capi_lock'. [Andrew, Stewart] > Populate and use the newly introduced 'struct capp' to > maintain the state of capp. > --- Thanks. Reviewed-by: Christophe Lombard <clombard@linux.vnet.ibm.com>
Le 08/01/2019 à 10:59, Vaibhav Jain a écrit : > 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(). > > Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> > Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com> > --- Reviewed-by: Frederic Barrat <fbarrat@linux.ibm.com> > Change-log > > v3: Use 'struct capp *' from struct phb4 instead of struct phb. > Minor typo fixed. [ Andrew ] > > v2: Removed the usage of global mutex 'capi_lock'. [Andrew, Stewart] > Populate and use the newly introduced 'struct capp' to > maintain the state of capp. > --- > hw/phb4.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++- > include/phb4.h | 1 + > 2 files changed, 97 insertions(+), 1 deletion(-) > > diff --git a/hw/phb4.c b/hw/phb4.c > index 229617c5..88b1a6fb 100644 > --- a/hw/phb4.c > +++ b/hw/phb4.c > @@ -2799,6 +2799,36 @@ 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 int64_t phb4_slot_sm_run_completed(struct pci_slot *slot, uint64_t err) > +{ > + struct phb4 *p = phb_to_phb4(slot->phb); > + > + /* Check if we are disabling the capp */ > + if (p->flags & PHB4_CAPP_DISABLE) { > + > + /* Unset struct capp so that we dont fall into a creset loop */ > + p->flags &= ~(PHB4_CAPP_DISABLE); > + p->capp->phb = NULL; > + p->capp->attached_pe = phb4_get_reserved_pe_number(&p->phb); > + > + /* Remove the host sync notifier is we are done.*/ > + opal_del_host_sync_notifier(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"); > + } > + } > + > + return OPAL_SUCCESS; > +} > + > static int64_t phb4_poll_link(struct pci_slot *slot) > { > struct phb4 *p = phb_to_phb4(slot->phb); > @@ -3155,6 +3185,42 @@ 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) > +{ > + uint64_t reg; > + struct capp *capp = p->capp; > + > + PHBINF(p, "CAPP: Deactivating\n"); > + > + /* Check if CAPP attached to the PHB and active */ > + if (!capp || capp->phb != &p->phb) { > + PHBDBG(p, "CAPP: Not attached to this PHB!\n"); > + return; > + } > + > + xscom_read(p->chip_id, p->pe_xscom + XPEC_NEST_CAPP_CNTL, ®); > + if (!(reg & PPC_BIT(0))) { > + /* Not in CAPI mode, no action required */ > + PHBERR(p, "CAPP: Not enabled!\n"); > + return; > + } > + > + /* CAPP should already be out of recovery in this function */ > + capp_xscom_read(capp, CAPP_ERR_STATUS_CTRL, ®); > + if (reg & PPC_BIT(0)) { > + PHBERR(p, "CAPP: Can't 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); > @@ -3215,6 +3281,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); > @@ -3318,6 +3387,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; > @@ -4491,12 +4561,37 @@ 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 = p->capp->phb ? OPAL_UNSUPPORTED : OPAL_SUCCESS; > 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 (capp->phb) { > + /* Kick start a creset */ > + 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"); > diff --git a/include/phb4.h b/include/phb4.h > index 60c1735d..da3d5d1f 100644 > --- a/include/phb4.h > +++ b/include/phb4.h > @@ -166,6 +166,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 */ >
diff --git a/hw/phb4.c b/hw/phb4.c index 229617c5..88b1a6fb 100644 --- a/hw/phb4.c +++ b/hw/phb4.c @@ -2799,6 +2799,36 @@ 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 int64_t phb4_slot_sm_run_completed(struct pci_slot *slot, uint64_t err) +{ + struct phb4 *p = phb_to_phb4(slot->phb); + + /* Check if we are disabling the capp */ + if (p->flags & PHB4_CAPP_DISABLE) { + + /* Unset struct capp so that we dont fall into a creset loop */ + p->flags &= ~(PHB4_CAPP_DISABLE); + p->capp->phb = NULL; + p->capp->attached_pe = phb4_get_reserved_pe_number(&p->phb); + + /* Remove the host sync notifier is we are done.*/ + opal_del_host_sync_notifier(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"); + } + } + + return OPAL_SUCCESS; +} + static int64_t phb4_poll_link(struct pci_slot *slot) { struct phb4 *p = phb_to_phb4(slot->phb); @@ -3155,6 +3185,42 @@ 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) +{ + uint64_t reg; + struct capp *capp = p->capp; + + PHBINF(p, "CAPP: Deactivating\n"); + + /* Check if CAPP attached to the PHB and active */ + if (!capp || capp->phb != &p->phb) { + PHBDBG(p, "CAPP: Not attached to this PHB!\n"); + return; + } + + xscom_read(p->chip_id, p->pe_xscom + XPEC_NEST_CAPP_CNTL, ®); + if (!(reg & PPC_BIT(0))) { + /* Not in CAPI mode, no action required */ + PHBERR(p, "CAPP: Not enabled!\n"); + return; + } + + /* CAPP should already be out of recovery in this function */ + capp_xscom_read(capp, CAPP_ERR_STATUS_CTRL, ®); + if (reg & PPC_BIT(0)) { + PHBERR(p, "CAPP: Can't 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); @@ -3215,6 +3281,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); @@ -3318,6 +3387,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; @@ -4491,12 +4561,37 @@ 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 = p->capp->phb ? OPAL_UNSUPPORTED : OPAL_SUCCESS; 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 (capp->phb) { + /* Kick start a creset */ + 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"); diff --git a/include/phb4.h b/include/phb4.h index 60c1735d..da3d5d1f 100644 --- a/include/phb4.h +++ b/include/phb4.h @@ -166,6 +166,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 */