summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2019-03-20 19:56:55 +1100
committerStewart Smith <stewart@linux.ibm.com>2019-03-28 15:24:13 +1100
commitb8b4c79d44191c09d75ffe6204ab9ce1191491d4 (patch)
treeb9eb36f0f0cca69ed22d9e6ee4be59ce86691126
parente89d3f32d2167f9821c60c4f5ff54a6d79a0a41a (diff)
downloadblackbird-skiboot-b8b4c79d44191c09d75ffe6204ab9ce1191491d4.tar.gz
blackbird-skiboot-b8b4c79d44191c09d75ffe6204ab9ce1191491d4.zip
hw/phb4: Factor out PERST control
Some time ago Mikey added some code work around a bug we found where a certain RAID card wouldn't come back again after a fast-reboot. The workaround is setting the Link Disable bit before asserting PERST and clear it after de-asserting PERST. Currently we do this in the FRESET path, but not in the CRESET path. This patch moves the PERST control into its own function to reduce duplication and to the workaround is applied in all circumstances. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
-rw-r--r--hw/phb4.c64
1 files changed, 36 insertions, 28 deletions
diff --git a/hw/phb4.c b/hw/phb4.c
index 4083d715..75a306a7 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -2870,6 +2870,34 @@ static unsigned int phb4_get_max_link_speed(struct phb4 *p, struct dt_node *np)
return max_link_speed;
}
+static void phb4_assert_perst(struct pci_slot *slot, bool assert)
+{
+ struct phb4 *p = phb_to_phb4(slot->phb);
+ uint16_t linkctl;
+ uint64_t reg;
+
+ /*
+ * Disable the link before asserting PERST. The Cursed RAID card
+ * in ozrom1 (9005:028c) has problems coming back if PERST is asserted
+ * while link is active. To work around the problem we assert the link
+ * disable bit before asserting PERST. Asserting the secondary reset
+ * bit in the btctl register also works.
+ */
+ phb4_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_LCTL, &linkctl);
+ reg = in_be64(p->regs + PHB_PCIE_CRESET);
+
+ if (assert) {
+ linkctl |= PCICAP_EXP_LCTL_LINK_DIS;
+ reg &= ~PHB_PCIE_CRESET_PERST_N;
+ } else {
+ linkctl &= ~PCICAP_EXP_LCTL_LINK_DIS;
+ reg |= PHB_PCIE_CRESET_PERST_N;
+ }
+
+ out_be64(p->regs + PHB_PCIE_CRESET, reg);
+ phb4_pcicfg_write16(&p->phb, 0, p->ecap + PCICAP_EXP_LCTL, linkctl);
+}
+
static int64_t phb4_hreset(struct pci_slot *slot)
{
struct phb4 *p = phb_to_phb4(slot->phb);
@@ -2932,7 +2960,6 @@ static int64_t phb4_freset(struct pci_slot *slot)
{
struct phb4 *p = phb_to_phb4(slot->phb);
uint64_t reg;
- uint16_t reg16;
switch(slot->state) {
case PHB4_SLOT_NORMAL:
@@ -2945,19 +2972,11 @@ static int64_t phb4_freset(struct pci_slot *slot)
PHBDBG(p, "FRESET: Prepare for link down\n");
phb4_prepare_link_change(slot, false);
- phb4_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_LCTL,
- &reg16);
- reg16 |= PCICAP_EXP_LCTL_LINK_DIS;
- phb4_pcicfg_write16(&p->phb, 0, p->ecap + PCICAP_EXP_LCTL,
- reg16);
-
if (!p->skip_perst) {
PHBDBG(p, "FRESET: Assert\n");
- reg = in_be64(p->regs + PHB_PCIE_CRESET);
- reg &= ~PHB_PCIE_CRESET_PERST_N;
- out_be64(p->regs + PHB_PCIE_CRESET, reg);
- pci_slot_set_state(slot,
- PHB4_SLOT_FRESET_ASSERT_DELAY);
+ phb4_assert_perst(slot, true);
+ pci_slot_set_state(slot, PHB4_SLOT_FRESET_ASSERT_DELAY);
+
/* 250ms assert time aligns with powernv */
return pci_slot_set_sm_timeout(slot, msecs_to_tb(250));
}
@@ -2979,21 +2998,12 @@ static int64_t phb4_freset(struct pci_slot *slot)
}
PHBDBG(p, "FRESET: Deassert\n");
- reg = in_be64(p->regs + PHB_PCIE_CRESET);
- reg |= PHB_PCIE_CRESET_PERST_N;
- out_be64(p->regs + PHB_PCIE_CRESET, reg);
- pci_slot_set_state(slot,
- PHB4_SLOT_FRESET_DEASSERT_DELAY);
+ phb4_assert_perst(slot, false);
+ pci_slot_set_state(slot, PHB4_SLOT_FRESET_DEASSERT_DELAY);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(1));
- /* Move on to link poll right away */
- return pci_slot_set_sm_timeout(slot, 1);
case PHB4_SLOT_FRESET_DEASSERT_DELAY:
PHBDBG(p, "FRESET: Starting training\n");
- phb4_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_LCTL,
- &reg16);
- reg16 &= ~(PCICAP_EXP_LCTL_LINK_DIS);
- phb4_pcicfg_write16(&p->phb, 0, p->ecap + PCICAP_EXP_LCTL,
- reg16);
phb4_training_trace(p);
@@ -3212,7 +3222,7 @@ static int64_t phb4_creset(struct pci_slot *slot)
{
struct phb4 *p = phb_to_phb4(slot->phb);
struct capp *capp = p->capp;
- uint64_t pbcq_status, reg;
+ uint64_t pbcq_status;
uint64_t creset_time, wait_time;
/* Don't even try fixing a broken PHB */
@@ -3252,9 +3262,7 @@ static int64_t phb4_creset(struct pci_slot *slot)
p->flags |= PHB4_CFG_USE_ASB | PHB4_AIB_FENCED;
/* Assert PREST before clearing errors */
- reg = phb4_read_reg(p, PHB_PCIE_CRESET);
- reg &= ~PHB_PCIE_CRESET_PERST_N;
- phb4_write_reg(p, PHB_PCIE_CRESET, reg);
+ phb4_assert_perst(slot, true);
/* Clear errors, following the proper sequence */
phb4_err_clear(p);
OpenPOWER on IntegriCloud