diff options
Diffstat (limited to 'hw/phb3.c')
-rw-r--r-- | hw/phb3.c | 31 |
1 files changed, 29 insertions, 2 deletions
@@ -1964,8 +1964,19 @@ static void phb3_setup_for_link_up(struct phb3 *p) } } +static int64_t phb3_retry_state(struct phb3 *p) +{ + if (p->retry_state <= PHB3_STATE_FUNCTIONAL) + return OPAL_WRONG_STATE; + + p->delay_tgt_tb = 0; + p->state = p->retry_state; + return p->phb.ops->poll(&p->phb); +} + static int64_t phb3_sm_link_poll(struct phb3 *p) { + int64_t rc; uint64_t reg; /* This is the state machine to wait for the link to come @@ -1992,6 +2003,10 @@ static int64_t phb3_sm_link_poll(struct phb3 *p) } else if (p->retries-- == 0) { PHBDBG(p, "Timeout waiting for electrical link\n"); PHBDBG(p, "DLP train control: 0x%016llx\n", reg); + rc = phb3_retry_state(p); + if (rc >= OPAL_SUCCESS) + return rc; + /* No link, we still mark the PHB as functional */ p->state = PHB3_STATE_FUNCTIONAL; return OPAL_SUCCESS; @@ -2013,6 +2028,10 @@ static int64_t phb3_sm_link_poll(struct phb3 *p) if (p->retries-- == 0) { PHBDBG(p, "Timeout waiting for link up\n"); PHBDBG(p, "DLP train control: 0x%016llx\n", reg); + rc = phb3_retry_state(p); + if (rc >= OPAL_SUCCESS) + return rc; + /* No link, we still mark the PHB as functional */ p->state = PHB3_STATE_FUNCTIONAL; return OPAL_SUCCESS; @@ -2127,12 +2146,17 @@ static int64_t phb3_sm_fundamental_reset(struct phb3 *p) switch(p->state) { case PHB3_STATE_FUNCTIONAL: - PHBINF(p, "Performing PERST...\n"); - /* Prepare for link going down */ phb3_setup_for_link_down(p); + /* Fall-through */ + case PHB3_STATE_FRESET_START: + if (p->state == PHB3_STATE_FRESET_START) { + PHBDBG(p, "Slot freset: Retrying\n"); + p->retry_state = 0; + } /* Assert PERST */ + PHBINF(p, "Performing PERST...\n"); reg = in_be64(p->regs + PHB_RESET); reg &= ~0x2000000000000000ul; out_be64(p->regs + PHB_RESET, reg); @@ -2176,6 +2200,8 @@ static int64_t phb3_fundamental_reset(struct phb *phb) return OPAL_HARDWARE; } + /* Allow to retry fundamental reset */ + p->retry_state = PHB3_STATE_FRESET_START; p->flags |= PHB3_CFG_BLOCKED; return phb3_sm_fundamental_reset(p); } @@ -2456,6 +2482,7 @@ static int64_t phb3_poll(struct phb *phb) case PHB3_STATE_HRESET_DELAY: case PHB3_STATE_HRESET_DELAY2: return phb3_sm_hot_reset(p); + case PHB3_STATE_FRESET_START: case PHB3_STATE_FRESET_ASSERT_DELAY: case PHB3_STATE_FRESET_DEASSERT_DELAY: return phb3_sm_fundamental_reset(p); |