Commit bec7c79c authored by Byczkowski, Jakub's avatar Byczkowski, Jakub Committed by Doug Ledford

IB/hfi1: Modify handling of physical link state by Host Driver

Ensure states returned to the Fabric Manager are consistent with
the OPA specification by caching the physical state along with the
logical state.
Reviewed-by: default avatarStuart Summers <john.s.summers@intel.com>
Reviewed-by: default avatarIra Weiny <ira.weiny@intel.com>
Reviewed-by: default avatarAndrzej Kotlowski <andrzej.kotlowski@intel.com>
Signed-off-by: default avatarJakub Byczkowski <jakub.byczkowski@intel.com>
Signed-off-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent d5438983
...@@ -1066,6 +1066,8 @@ static int thermal_init(struct hfi1_devdata *dd); ...@@ -1066,6 +1066,8 @@ static int thermal_init(struct hfi1_devdata *dd);
static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state, static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state,
int msecs); int msecs);
static int wait_physical_linkstate(struct hfi1_pportdata *ppd, u32 state,
int msecs);
static void read_planned_down_reason_code(struct hfi1_devdata *dd, u8 *pdrrc); static void read_planned_down_reason_code(struct hfi1_devdata *dd, u8 *pdrrc);
static void read_link_down_reason(struct hfi1_devdata *dd, u8 *ldr); static void read_link_down_reason(struct hfi1_devdata *dd, u8 *ldr);
static void handle_temp_err(struct hfi1_devdata *dd); static void handle_temp_err(struct hfi1_devdata *dd);
...@@ -10028,28 +10030,6 @@ static void set_lidlmc(struct hfi1_pportdata *ppd) ...@@ -10028,28 +10030,6 @@ static void set_lidlmc(struct hfi1_pportdata *ppd)
sdma_update_lmc(dd, mask, ppd->lid); sdma_update_lmc(dd, mask, ppd->lid);
} }
static int wait_phy_linkstate(struct hfi1_devdata *dd, u32 state, u32 msecs)
{
unsigned long timeout;
u32 curr_state;
timeout = jiffies + msecs_to_jiffies(msecs);
while (1) {
curr_state = read_physical_state(dd);
if (curr_state == state)
break;
if (time_after(jiffies, timeout)) {
dd_dev_err(dd,
"timeout waiting for phy link state 0x%x, current state is 0x%x\n",
state, curr_state);
return -ETIMEDOUT;
}
usleep_range(1950, 2050); /* sleep 2ms-ish */
}
return 0;
}
static const char *state_completed_string(u32 completed) static const char *state_completed_string(u32 completed)
{ {
static const char * const state_completed[] = { static const char * const state_completed[] = {
...@@ -10283,7 +10263,7 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason) ...@@ -10283,7 +10263,7 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
if (do_wait) { if (do_wait) {
/* it can take a while for the link to go down */ /* it can take a while for the link to go down */
ret = wait_phy_linkstate(dd, PLS_OFFLINE, 10000); ret = wait_physical_linkstate(ppd, PLS_OFFLINE, 10000);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -10536,6 +10516,19 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state) ...@@ -10536,6 +10516,19 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state)
goto unexpected; goto unexpected;
} }
/*
* Wait for Link_Up physical state.
* Physical and Logical states should already be
* be transitioned to LinkUp and LinkInit respectively.
*/
ret = wait_physical_linkstate(ppd, PLS_LINKUP, 1000);
if (ret) {
dd_dev_err(dd,
"%s: physical state did not change to LINK-UP\n",
__func__);
break;
}
ret = wait_logical_linkstate(ppd, IB_PORT_INIT, 1000); ret = wait_logical_linkstate(ppd, IB_PORT_INIT, 1000);
if (ret) { if (ret) {
dd_dev_err(dd, dd_dev_err(dd,
...@@ -10649,6 +10642,8 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state) ...@@ -10649,6 +10642,8 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state)
*/ */
if (ret) if (ret)
goto_offline(ppd, 0); goto_offline(ppd, 0);
else
cache_physical_state(ppd);
break; break;
case HLS_DN_DISABLE: case HLS_DN_DISABLE:
/* link is disabled */ /* link is disabled */
...@@ -10673,6 +10668,13 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state) ...@@ -10673,6 +10668,13 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state)
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
ret = wait_physical_linkstate(ppd, PLS_DISABLED, 10000);
if (ret) {
dd_dev_err(dd,
"%s: physical state did not change to DISABLED\n",
__func__);
break;
}
dc_shutdown(dd); dc_shutdown(dd);
} }
ppd->host_link_state = HLS_DN_DISABLE; ppd->host_link_state = HLS_DN_DISABLE;
...@@ -10690,6 +10692,7 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state) ...@@ -10690,6 +10692,7 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state)
if (ppd->host_link_state != HLS_DN_POLL) if (ppd->host_link_state != HLS_DN_POLL)
goto unexpected; goto unexpected;
ppd->host_link_state = HLS_VERIFY_CAP; ppd->host_link_state = HLS_VERIFY_CAP;
cache_physical_state(ppd);
break; break;
case HLS_GOING_UP: case HLS_GOING_UP:
if (ppd->host_link_state != HLS_VERIFY_CAP) if (ppd->host_link_state != HLS_VERIFY_CAP)
...@@ -12663,21 +12666,56 @@ static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state, ...@@ -12663,21 +12666,56 @@ static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
u8 hfi1_ibphys_portstate(struct hfi1_pportdata *ppd) /*
* Read the physical hardware link state and set the driver's cached value
* of it.
*/
void cache_physical_state(struct hfi1_pportdata *ppd)
{ {
u32 pstate; u32 read_pstate;
u32 ib_pstate; u32 ib_pstate;
pstate = read_physical_state(ppd->dd); read_pstate = read_physical_state(ppd->dd);
ib_pstate = chip_to_opa_pstate(ppd->dd, pstate); ib_pstate = chip_to_opa_pstate(ppd->dd, read_pstate);
if (ppd->last_pstate != ib_pstate) { /* check if OPA pstate changed */
if (chip_to_opa_pstate(ppd->dd, ppd->pstate) != ib_pstate) {
dd_dev_info(ppd->dd, dd_dev_info(ppd->dd,
"%s: physical state changed to %s (0x%x), phy 0x%x\n", "%s: physical state changed to %s (0x%x), phy 0x%x\n",
__func__, opa_pstate_name(ib_pstate), ib_pstate, __func__, opa_pstate_name(ib_pstate), ib_pstate,
pstate); read_pstate);
ppd->last_pstate = ib_pstate;
} }
return ib_pstate; ppd->pstate = read_pstate;
}
/*
* wait_physical_linkstate - wait for an physical link state change to occur
* @ppd: port device
* @state: the state to wait for
* @msecs: the number of milliseconds to wait
*
* Wait up to msecs milliseconds for physical link state change to occur.
* Returns 0 if state reached, otherwise -ETIMEDOUT.
*/
static int wait_physical_linkstate(struct hfi1_pportdata *ppd, u32 state,
int msecs)
{
unsigned long timeout;
timeout = jiffies + msecs_to_jiffies(msecs);
while (1) {
cache_physical_state(ppd);
if (ppd->pstate == state)
break;
if (time_after(jiffies, timeout)) {
dd_dev_err(ppd->dd,
"timeout waiting for phy link state 0x%x, current state is 0x%x\n",
state, ppd->pstate);
return -ETIMEDOUT;
}
usleep_range(1950, 2050); /* sleep 2ms-ish */
}
return 0;
} }
#define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \ #define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \
...@@ -14781,7 +14819,7 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, ...@@ -14781,7 +14819,7 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
/* start in offline */ /* start in offline */
ppd->host_link_state = HLS_DN_OFFLINE; ppd->host_link_state = HLS_DN_OFFLINE;
init_vl_arb_caches(ppd); init_vl_arb_caches(ppd);
ppd->last_pstate = 0xff; /* invalid value */ ppd->pstate = PLS_OFFLINE;
} }
dd->link_default = HLS_DN_POLL; dd->link_default = HLS_DN_POLL;
......
...@@ -744,6 +744,7 @@ int is_bx(struct hfi1_devdata *dd); ...@@ -744,6 +744,7 @@ int is_bx(struct hfi1_devdata *dd);
u32 read_physical_state(struct hfi1_devdata *dd); u32 read_physical_state(struct hfi1_devdata *dd);
u32 chip_to_opa_pstate(struct hfi1_devdata *dd, u32 chip_pstate); u32 chip_to_opa_pstate(struct hfi1_devdata *dd, u32 chip_pstate);
u32 get_logical_state(struct hfi1_pportdata *ppd); u32 get_logical_state(struct hfi1_pportdata *ppd);
void cache_physical_state(struct hfi1_pportdata *ppd);
const char *opa_lstate_name(u32 lstate); const char *opa_lstate_name(u32 lstate);
const char *opa_pstate_name(u32 pstate); const char *opa_pstate_name(u32 pstate);
u32 driver_physical_state(struct hfi1_pportdata *ppd); u32 driver_physical_state(struct hfi1_pportdata *ppd);
...@@ -1354,7 +1355,6 @@ void hfi1_quiet_serdes(struct hfi1_pportdata *ppd); ...@@ -1354,7 +1355,6 @@ void hfi1_quiet_serdes(struct hfi1_pportdata *ppd);
void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt); void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt);
u32 hfi1_read_cntrs(struct hfi1_devdata *dd, char **namep, u64 **cntrp); u32 hfi1_read_cntrs(struct hfi1_devdata *dd, char **namep, u64 **cntrp);
u32 hfi1_read_portcntrs(struct hfi1_pportdata *ppd, char **namep, u64 **cntrp); u32 hfi1_read_portcntrs(struct hfi1_pportdata *ppd, char **namep, u64 **cntrp);
u8 hfi1_ibphys_portstate(struct hfi1_pportdata *ppd);
int hfi1_get_ib_cfg(struct hfi1_pportdata *ppd, int which); int hfi1_get_ib_cfg(struct hfi1_pportdata *ppd, int which);
int hfi1_set_ib_cfg(struct hfi1_pportdata *ppd, int which, u32 val); int hfi1_set_ib_cfg(struct hfi1_pportdata *ppd, int which, u32 val);
int hfi1_set_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt, u16 jkey); int hfi1_set_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt, u16 jkey);
......
...@@ -906,10 +906,12 @@ static inline int set_armed_to_active(struct hfi1_ctxtdata *rcd, ...@@ -906,10 +906,12 @@ static inline int set_armed_to_active(struct hfi1_ctxtdata *rcd,
sc = hfi1_9B_get_sc5(hdr, packet->rhf); sc = hfi1_9B_get_sc5(hdr, packet->rhf);
} }
if (sc != SC15_PACKET) { if (sc != SC15_PACKET) {
int hwstate = read_logical_state(dd); int hwstate = driver_lstate(rcd->ppd);
if (hwstate != LSTATE_ACTIVE) { if (hwstate != IB_PORT_ACTIVE) {
dd_dev_info(dd, "Unexpected link state %d\n", hwstate); dd_dev_info(dd,
"Unexpected link state %s\n",
opa_lstate_name(hwstate));
return 0; return 0;
} }
......
...@@ -663,7 +663,7 @@ struct hfi1_pportdata { ...@@ -663,7 +663,7 @@ struct hfi1_pportdata {
u8 link_enabled; /* link enabled? */ u8 link_enabled; /* link enabled? */
u8 linkinit_reason; u8 linkinit_reason;
u8 local_tx_rate; /* rate given to 8051 firmware */ u8 local_tx_rate; /* rate given to 8051 firmware */
u8 last_pstate; /* info only */ u8 pstate; /* info only */
u8 qsfp_retry_count; u8 qsfp_retry_count;
/* placeholders for IB MAD packet settings */ /* placeholders for IB MAD packet settings */
...@@ -1330,6 +1330,22 @@ static inline u32 driver_lstate(struct hfi1_pportdata *ppd) ...@@ -1330,6 +1330,22 @@ static inline u32 driver_lstate(struct hfi1_pportdata *ppd)
return ppd->lstate; return ppd->lstate;
} }
/* return the driver's idea of the physical OPA port state */
static inline u32 driver_pstate(struct hfi1_pportdata *ppd)
{
/*
* The driver does some processing from the time the physical
* link state is at LINKUP to the time the SM can be notified
* as such. Return IB_PORTPHYSSTATE_TRAINING until the software
* state is ready.
*/
if (ppd->pstate == PLS_LINKUP &&
!(ppd->host_link_state & HLS_UP))
return IB_PORTPHYSSTATE_TRAINING;
else
return chip_to_opa_pstate(ppd->dd, ppd->pstate);
}
void receive_interrupt_work(struct work_struct *work); void receive_interrupt_work(struct work_struct *work);
/* extract service channel from header and rhf */ /* extract service channel from header and rhf */
......
...@@ -113,7 +113,7 @@ static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len) ...@@ -113,7 +113,7 @@ static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len)
return; return;
/* o14-3.2.1 */ /* o14-3.2.1 */
if (ppd_from_ibp(ibp)->lstate != IB_PORT_ACTIVE) if (driver_lstate(ppd_from_ibp(ibp)) != IB_PORT_ACTIVE)
return; return;
/* o14-2 */ /* o14-2 */
...@@ -615,7 +615,7 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, ...@@ -615,7 +615,7 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
ppd->offline_disabled_reason; ppd->offline_disabled_reason;
pi->port_states.portphysstate_portstate = pi->port_states.portphysstate_portstate =
(hfi1_ibphys_portstate(ppd) << 4) | state; (driver_pstate(ppd) << 4) | state;
pi->mkeyprotect_lmc = (ibp->rvp.mkeyprot << 6) | ppd->lmc; pi->mkeyprotect_lmc = (ibp->rvp.mkeyprot << 6) | ppd->lmc;
...@@ -1791,7 +1791,7 @@ static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data, ...@@ -1791,7 +1791,7 @@ static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
ppd->offline_disabled_reason; ppd->offline_disabled_reason;
psi->port_states.portphysstate_portstate = psi->port_states.portphysstate_portstate =
(hfi1_ibphys_portstate(ppd) << 4) | (lstate & 0xf); (driver_pstate(ppd) << 4) | (lstate & 0xf);
psi->link_width_downgrade_tx_active = psi->link_width_downgrade_tx_active =
cpu_to_be16(ppd->link_width_downgrade_tx_active); cpu_to_be16(ppd->link_width_downgrade_tx_active);
psi->link_width_downgrade_rx_active = psi->link_width_downgrade_rx_active =
......
...@@ -1354,7 +1354,7 @@ static int query_port(struct rvt_dev_info *rdi, u8 port_num, ...@@ -1354,7 +1354,7 @@ static int query_port(struct rvt_dev_info *rdi, u8 port_num,
props->lmc = ppd->lmc; props->lmc = ppd->lmc;
/* OPA logical states match IB logical states */ /* OPA logical states match IB logical states */
props->state = driver_lstate(ppd); props->state = driver_lstate(ppd);
props->phys_state = hfi1_ibphys_portstate(ppd); props->phys_state = driver_pstate(ppd);
props->gid_tbl_len = HFI1_GUIDS_PER_PORT; props->gid_tbl_len = HFI1_GUIDS_PER_PORT;
props->active_width = (u8)opa_width_to_ib(ppd->link_width_active); props->active_width = (u8)opa_width_to_ib(ppd->link_width_active);
/* see rate_show() in ib core/sysfs.c */ /* see rate_show() in ib core/sysfs.c */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment