[Skiboot] [RFC PATCH 06/23] core/pci-slot: Add pci_slot_generic_freset()
Oliver O'Halloran
oohall at gmail.com
Wed Apr 3 20:09:03 AEDT 2019
Add a generic function that can use the assert_perst() and
set_power_state() slot operations to do fundemental reset of the
slot.
Signed-off-by: Oliver O'Halloran <oohall at gmail.com>
---
core/pci-slot.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++
hw/phb4.c | 5 ++--
include/pci-slot.h | 6 ++++
3 files changed, 81 insertions(+), 2 deletions(-)
diff --git a/core/pci-slot.c b/core/pci-slot.c
index 497d0a47f426..14dd95ec0dd1 100644
--- a/core/pci-slot.c
+++ b/core/pci-slot.c
@@ -19,6 +19,7 @@
#include <pci-cfg.h>
#include <pci.h>
#include <pci-slot.h>
+#include <stack.h>
/* Debugging options */
#define PCI_SLOT_PREFIX "PCI-SLOT-%016llx "
@@ -114,6 +115,77 @@ static int64_t pci_slot_run_sm(struct pci_slot *slot)
return ret;
}
+int64_t pci_slot_generic_freset(struct pci_slot *slot)
+{
+ uint16_t bdfn = slot->pd ? slot->pd->bdfn : 0;
+ struct phb *phb = slot->phb;
+ int64_t rc;
+
+ /* We need atleast one of them to do an FRESET */
+ assert(slot->ops.set_power_state || slot->ops.assert_perst);
+ // not strictly required...
+ assert(slot->ops.prepare_link_change);
+
+ switch(slot->state) {
+ case PCI_SLOT_STATE_NORMAL:
+ case PCI_SLOT_FRESET_START:
+ PCIERR(phb, bdfn, "FRESET: Prepare for link down\n");
+
+ // FIXME: Handle errors
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, false);
+ if (slot->ops.assert_perst)
+ slot->ops.assert_perst(slot, true);
+
+ /*
+ * If we don't have power control then skip those states
+ * and go straight to de-assert after 250ms.
+ */
+ if (!slot->ops.set_power_state) {
+ pci_slot_set_state(slot, PCI_SLOT_FRESET_LIFT_PERST);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(250));
+ }
+
+ pci_slot_set_state(slot, PCI_SLOT_FRESET_POWER_OFF);
+
+ /* fallthrough */
+ case PCI_SLOT_FRESET_POWER_OFF:
+ rc = slot->ops.set_power_state(slot, PCI_SLOT_POWER_OFF);
+ if (rc > 0)
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(rc));
+ /* XXX: error handling */
+
+ /* leave power off for 250ms before turning the slot back on */
+ PCIERR(phb, bdfn, "FRESET: Slot powered off\n");
+ pci_slot_set_state(slot, PCI_SLOT_FRESET_POWER_ON);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(250));
+
+ case PCI_SLOT_FRESET_POWER_ON:
+ rc = slot->ops.set_power_state(slot, PCI_SLOT_POWER_ON);
+ if (rc > 0)
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(rc));
+ /* XXX: error handling */
+ PCIERR(phb, bdfn, "FRESET: Slot powered on\n");
+
+ /* fallthrough */
+ case PCI_SLOT_FRESET_LIFT_PERST:
+ PCIDBG(phb, bdfn, "FRESET: Deassert\n");
+ if (slot->ops.assert_perst)
+ slot->ops.assert_perst(slot, false);
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_LINK_START_POLL);
+ return slot->ops.poll_link(slot);
+ default:
+ PCIERR(phb, bdfn, "Unexpected slot state %08x\n", slot->state);
+ }
+
+ PCIERR(phb, bdfn, "Uhh how did we get here???\n");
+ backtrace();
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+
+ return OPAL_HARDWARE;
+}
+
void pci_slot_add_dt_properties(struct pci_slot *slot,
struct dt_node *np)
{
diff --git a/hw/phb4.c b/hw/phb4.c
index bcd998d910af..591872c31c02 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -2939,6 +2939,9 @@ static void phb4_assert_perst(struct pci_slot *slot, bool assert)
} else {
linkctl &= ~PCICAP_EXP_LCTL_LINK_DIS;
reg |= PHB_PCIE_CRESET_PERST_N;
+
+ /* Clear link errors before we deassert PERST */
+ phb4_err_clear_regb(p);
}
out_be64(p->regs + PHB_PCIE_CRESET, reg);
@@ -3034,8 +3037,6 @@ static int64_t phb4_freset(struct pci_slot *slot)
p->skip_perst = false;
/* fall through */
case PHB4_SLOT_FRESET_ASSERT_DELAY:
- /* Clear link errors before we deassert PERST */
- phb4_err_clear_regb(p);
if (pci_tracing) {
/* Enable tracing */
diff --git a/include/pci-slot.h b/include/pci-slot.h
index cb36d7b6df5a..fec11ccf46c2 100644
--- a/include/pci-slot.h
+++ b/include/pci-slot.h
@@ -134,6 +134,10 @@ struct pci_slot_ops {
#define PCI_SLOT_STATE_HRESET_HOLD (PCI_SLOT_STATE_HRESET + 2)
#define PCI_SLOT_STATE_FRESET 0x00000300
#define PCI_SLOT_STATE_FRESET_POWER_OFF (PCI_SLOT_STATE_FRESET + 1)
+#define PCI_SLOT_FRESET_START (PCI_SLOT_STATE_FRESET + 1)
+#define PCI_SLOT_FRESET_POWER_OFF (PCI_SLOT_STATE_FRESET + 2)
+#define PCI_SLOT_FRESET_POWER_ON (PCI_SLOT_STATE_FRESET + 3)
+#define PCI_SLOT_FRESET_LIFT_PERST (PCI_SLOT_STATE_FRESET + 4)
#define PCI_SLOT_STATE_CRESET 0x00000400
#define PCI_SLOT_STATE_CRESET_START (PCI_SLOT_STATE_CRESET + 1)
#define PCI_SLOT_STATE_GPOWER 0x00000500
@@ -282,6 +286,8 @@ extern struct pci_slot *pci_slot_find(uint64_t id);
extern void pci_slot_add_loc(struct pci_slot *slot,
struct dt_node *np, const char *label);
+int64_t pci_slot_generic_freset(struct pci_slot *slot);
+
/* DT based slot map */
extern struct dt_node *dt_slots;
--
2.20.1
More information about the Skiboot
mailing list