diff options
| -rw-r--r-- | drivers/infiniband/hw/hfi1/chip.c | 85 | ||||
| -rw-r--r-- | drivers/infiniband/hw/hfi1/chip.h | 1 |
2 files changed, 65 insertions, 21 deletions
diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index b2ed4b9cda6e..1c810d65721a 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c | |||
| @@ -1066,6 +1066,8 @@ static int read_idle_sma(struct hfi1_devdata *dd, u64 *data); | |||
| 1066 | static int thermal_init(struct hfi1_devdata *dd); | 1066 | static int thermal_init(struct hfi1_devdata *dd); |
| 1067 | 1067 | ||
| 1068 | static void update_statusp(struct hfi1_pportdata *ppd, u32 state); | 1068 | static void update_statusp(struct hfi1_pportdata *ppd, u32 state); |
| 1069 | static int wait_phys_link_offline_substates(struct hfi1_pportdata *ppd, | ||
| 1070 | int msecs); | ||
| 1069 | static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state, | 1071 | static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state, |
| 1070 | int msecs); | 1072 | int msecs); |
| 1071 | static void log_state_transition(struct hfi1_pportdata *ppd, u32 state); | 1073 | static void log_state_transition(struct hfi1_pportdata *ppd, u32 state); |
| @@ -10305,6 +10307,7 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason) | |||
| 10305 | { | 10307 | { |
| 10306 | struct hfi1_devdata *dd = ppd->dd; | 10308 | struct hfi1_devdata *dd = ppd->dd; |
| 10307 | u32 previous_state; | 10309 | u32 previous_state; |
| 10310 | int offline_state_ret; | ||
| 10308 | int ret; | 10311 | int ret; |
| 10309 | 10312 | ||
| 10310 | update_lcb_cache(dd); | 10313 | update_lcb_cache(dd); |
| @@ -10326,28 +10329,11 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason) | |||
| 10326 | ppd->offline_disabled_reason = | 10329 | ppd->offline_disabled_reason = |
| 10327 | HFI1_ODR_MASK(OPA_LINKDOWN_REASON_TRANSIENT); | 10330 | HFI1_ODR_MASK(OPA_LINKDOWN_REASON_TRANSIENT); |
| 10328 | 10331 | ||
| 10329 | /* | 10332 | offline_state_ret = wait_phys_link_offline_substates(ppd, 10000); |
| 10330 | * Wait for offline transition. It can take a while for | 10333 | if (offline_state_ret < 0) |
| 10331 | * the link to go down. | 10334 | return offline_state_ret; |
| 10332 | */ | ||
| 10333 | ret = wait_physical_linkstate(ppd, PLS_OFFLINE, 10000); | ||
| 10334 | if (ret < 0) | ||
| 10335 | return ret; | ||
| 10336 | |||
| 10337 | /* | ||
| 10338 | * Now in charge of LCB - must be after the physical state is | ||
| 10339 | * offline.quiet and before host_link_state is changed. | ||
| 10340 | */ | ||
| 10341 | set_host_lcb_access(dd); | ||
| 10342 | write_csr(dd, DC_LCB_ERR_EN, ~0ull); /* watch LCB errors */ | ||
| 10343 | |||
| 10344 | /* make sure the logical state is also down */ | ||
| 10345 | ret = wait_logical_linkstate(ppd, IB_PORT_DOWN, 1000); | ||
| 10346 | if (ret) | ||
| 10347 | force_logical_link_state_down(ppd); | ||
| 10348 | |||
| 10349 | ppd->host_link_state = HLS_LINK_COOLDOWN; /* LCB access allowed */ | ||
| 10350 | 10335 | ||
| 10336 | /* Disabling AOC transmitters */ | ||
| 10351 | if (ppd->port_type == PORT_TYPE_QSFP && | 10337 | if (ppd->port_type == PORT_TYPE_QSFP && |
| 10352 | ppd->qsfp_info.limiting_active && | 10338 | ppd->qsfp_info.limiting_active && |
| 10353 | qsfp_mod_present(ppd)) { | 10339 | qsfp_mod_present(ppd)) { |
| @@ -10365,6 +10351,30 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason) | |||
| 10365 | } | 10351 | } |
| 10366 | 10352 | ||
| 10367 | /* | 10353 | /* |
| 10354 | * Wait for the offline.Quiet transition if it hasn't happened yet. It | ||
| 10355 | * can take a while for the link to go down. | ||
| 10356 | */ | ||
| 10357 | if (offline_state_ret != PLS_OFFLINE_QUIET) { | ||
| 10358 | ret = wait_physical_linkstate(ppd, PLS_OFFLINE, 30000); | ||
| 10359 | if (ret < 0) | ||
| 10360 | return ret; | ||
| 10361 | } | ||
| 10362 | |||
| 10363 | /* | ||
| 10364 | * Now in charge of LCB - must be after the physical state is | ||
| 10365 | * offline.quiet and before host_link_state is changed. | ||
| 10366 | */ | ||
| 10367 | set_host_lcb_access(dd); | ||
| 10368 | write_csr(dd, DC_LCB_ERR_EN, ~0ull); /* watch LCB errors */ | ||
| 10369 | |||
| 10370 | /* make sure the logical state is also down */ | ||
| 10371 | ret = wait_logical_linkstate(ppd, IB_PORT_DOWN, 1000); | ||
| 10372 | if (ret) | ||
| 10373 | force_logical_link_state_down(ppd); | ||
| 10374 | |||
| 10375 | ppd->host_link_state = HLS_LINK_COOLDOWN; /* LCB access allowed */ | ||
| 10376 | |||
| 10377 | /* | ||
| 10368 | * The LNI has a mandatory wait time after the physical state | 10378 | * The LNI has a mandatory wait time after the physical state |
| 10369 | * moves to Offline.Quiet. The wait time may be different | 10379 | * moves to Offline.Quiet. The wait time may be different |
| 10370 | * depending on how the link went down. The 8051 firmware | 10380 | * depending on how the link went down. The 8051 firmware |
| @@ -12804,6 +12814,39 @@ static int wait_physical_linkstate(struct hfi1_pportdata *ppd, u32 state, | |||
| 12804 | return 0; | 12814 | return 0; |
| 12805 | } | 12815 | } |
| 12806 | 12816 | ||
| 12817 | /* | ||
| 12818 | * wait_phys_link_offline_quiet_substates - wait for any offline substate | ||
| 12819 | * @ppd: port device | ||
| 12820 | * @msecs: the number of milliseconds to wait | ||
| 12821 | * | ||
| 12822 | * Wait up to msecs milliseconds for any offline physical link | ||
| 12823 | * state change to occur. | ||
| 12824 | * Returns 0 if at least one state is reached, otherwise -ETIMEDOUT. | ||
| 12825 | */ | ||
| 12826 | static int wait_phys_link_offline_substates(struct hfi1_pportdata *ppd, | ||
| 12827 | int msecs) | ||
| 12828 | { | ||
| 12829 | u32 read_state; | ||
| 12830 | unsigned long timeout; | ||
| 12831 | |||
| 12832 | timeout = jiffies + msecs_to_jiffies(msecs); | ||
| 12833 | while (1) { | ||
| 12834 | read_state = read_physical_state(ppd->dd); | ||
| 12835 | if ((read_state & 0xF0) == PLS_OFFLINE) | ||
| 12836 | break; | ||
| 12837 | if (time_after(jiffies, timeout)) { | ||
| 12838 | dd_dev_err(ppd->dd, | ||
| 12839 | "timeout waiting for phy link offline.quiet substates. Read state 0x%x, %dms\n", | ||
| 12840 | read_state, msecs); | ||
| 12841 | return -ETIMEDOUT; | ||
| 12842 | } | ||
| 12843 | usleep_range(1950, 2050); /* sleep 2ms-ish */ | ||
| 12844 | } | ||
| 12845 | |||
| 12846 | log_state_transition(ppd, read_state); | ||
| 12847 | return read_state; | ||
| 12848 | } | ||
| 12849 | |||
| 12807 | #define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \ | 12850 | #define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \ |
| 12808 | (r &= ~SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK) | 12851 | (r &= ~SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK) |
| 12809 | 12852 | ||
diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h index b8345a60a0fb..461f937fe110 100644 --- a/drivers/infiniband/hw/hfi1/chip.h +++ b/drivers/infiniband/hw/hfi1/chip.h | |||
| @@ -204,6 +204,7 @@ | |||
| 204 | #define PLS_OFFLINE_READY_TO_QUIET_LT 0x92 | 204 | #define PLS_OFFLINE_READY_TO_QUIET_LT 0x92 |
| 205 | #define PLS_OFFLINE_REPORT_FAILURE 0x93 | 205 | #define PLS_OFFLINE_REPORT_FAILURE 0x93 |
| 206 | #define PLS_OFFLINE_READY_TO_QUIET_BCC 0x94 | 206 | #define PLS_OFFLINE_READY_TO_QUIET_BCC 0x94 |
| 207 | #define PLS_OFFLINE_QUIET_DURATION 0x95 | ||
| 207 | #define PLS_POLLING 0x20 | 208 | #define PLS_POLLING 0x20 |
| 208 | #define PLS_POLLING_QUIET 0x20 | 209 | #define PLS_POLLING_QUIET 0x20 |
| 209 | #define PLS_POLLING_ACTIVE 0x21 | 210 | #define PLS_POLLING_ACTIVE 0x21 |
