Commit dde05cbd authored by Mitko Haralanov's avatar Mitko Haralanov Committed by Roland Dreier

IB/qib: Hold links until tuning data is available

Hold the link state machine until the tuning data is read from the
QSFP EEPROM so correct tuning settings are applied before the state
machine attempts to bring the link up.  Link is also held on cable
unplug in case a different cable is used.
Signed-off-by: default avatarMitko Haralanov <mitko@qlogic.com>
Signed-off-by: default avatarMike Marciniszyn <mike.marciniszyn@qlogic.com>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent 44d75d3d
...@@ -2381,17 +2381,17 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd) ...@@ -2381,17 +2381,17 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd)
ppd->cpspec->ibcctrl_a |= SYM_MASK(IBCCtrlA_0, IBLinkEn); ppd->cpspec->ibcctrl_a |= SYM_MASK(IBCCtrlA_0, IBLinkEn);
set_vls(ppd); set_vls(ppd);
/* Hold the link state machine for mezz boards */
qib_set_ib_7322_lstate(ppd, 0,
QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
/* be paranoid against later code motion, etc. */ /* be paranoid against later code motion, etc. */
spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags); spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags);
ppd->p_rcvctrl |= SYM_MASK(RcvCtrl_0, RcvIBPortEnable); ppd->p_rcvctrl |= SYM_MASK(RcvCtrl_0, RcvIBPortEnable);
qib_write_kreg_port(ppd, krp_rcvctrl, ppd->p_rcvctrl); qib_write_kreg_port(ppd, krp_rcvctrl, ppd->p_rcvctrl);
spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags); spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
/* Hold the link state machine for mezz boards */
if (IS_QMH(dd) || IS_QME(dd))
qib_set_ib_7322_lstate(ppd, 0,
QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
/* Also enable IBSTATUSCHG interrupt. */ /* Also enable IBSTATUSCHG interrupt. */
val = qib_read_kreg_port(ppd, krp_errmask); val = qib_read_kreg_port(ppd, krp_errmask);
qib_write_kreg_port(ppd, krp_errmask, qib_write_kreg_port(ppd, krp_errmask,
...@@ -5229,6 +5229,8 @@ static int qib_7322_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs) ...@@ -5229,6 +5229,8 @@ static int qib_7322_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs)
QIBL_IB_AUTONEG_INPROG))) QIBL_IB_AUTONEG_INPROG)))
set_7322_ibspeed_fast(ppd, ppd->link_speed_enabled); set_7322_ibspeed_fast(ppd, ppd->link_speed_enabled);
if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG)) { if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG)) {
struct qib_qsfp_data *qd =
&ppd->cpspec->qsfp_data;
/* unlock the Tx settings, speed may change */ /* unlock the Tx settings, speed may change */
qib_write_kreg_port(ppd, krp_tx_deemph_override, qib_write_kreg_port(ppd, krp_tx_deemph_override,
SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
...@@ -5236,6 +5238,12 @@ static int qib_7322_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs) ...@@ -5236,6 +5238,12 @@ static int qib_7322_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs)
qib_cancel_sends(ppd); qib_cancel_sends(ppd);
/* on link down, ensure sane pcs state */ /* on link down, ensure sane pcs state */
qib_7322_mini_pcs_reset(ppd); qib_7322_mini_pcs_reset(ppd);
/* schedule the qsfp refresh which should turn the link
off */
if (ppd->dd->flags & QIB_HAS_QSFP) {
qd->t_insert = get_jiffies_64();
schedule_work(&qd->work);
}
spin_lock_irqsave(&ppd->sdma_lock, flags); spin_lock_irqsave(&ppd->sdma_lock, flags);
if (__qib_sdma_running(ppd)) if (__qib_sdma_running(ppd))
__qib_sdma_process_event(ppd, __qib_sdma_process_event(ppd,
...@@ -5591,8 +5599,17 @@ static void qsfp_7322_event(struct work_struct *work) ...@@ -5591,8 +5599,17 @@ static void qsfp_7322_event(struct work_struct *work)
qd = container_of(work, struct qib_qsfp_data, work); qd = container_of(work, struct qib_qsfp_data, work);
ppd = qd->ppd; ppd = qd->ppd;
pwrup = qd->t_insert + msecs_to_jiffies(QSFP_PWR_LAG_MSEC); pwrup = qd->t_insert +
msecs_to_jiffies(QSFP_PWR_LAG_MSEC - QSFP_MODPRS_LAG_MSEC);
/* Delay for 20 msecs to allow ModPrs resistor to setup */
mdelay(QSFP_MODPRS_LAG_MSEC);
if (!qib_qsfp_mod_present(ppd))
/* Set the physical link to disabled */
qib_set_ib_7322_lstate(ppd, 0,
QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
else {
/* /*
* Some QSFP's not only do not respond until the full power-up * Some QSFP's not only do not respond until the full power-up
* time, but may behave badly if we try. So hold off responding * time, but may behave badly if we try. So hold off responding
...@@ -5604,7 +5621,9 @@ static void qsfp_7322_event(struct work_struct *work) ...@@ -5604,7 +5621,9 @@ static void qsfp_7322_event(struct work_struct *work)
break; break;
msleep(20); msleep(20);
} }
ret = qib_refresh_qsfp_cache(ppd, &qd->cache); ret = qib_refresh_qsfp_cache(ppd, &qd->cache);
/* /*
* Need to change LE2 back to defaults if we couldn't * Need to change LE2 back to defaults if we couldn't
* read the cable type (to handle cable swaps), so do this * read the cable type (to handle cable swaps), so do this
...@@ -5622,7 +5641,20 @@ static void qsfp_7322_event(struct work_struct *work) ...@@ -5622,7 +5641,20 @@ static void qsfp_7322_event(struct work_struct *work)
} else } else
le2 = LE2_DEFAULT; le2 = LE2_DEFAULT;
ibsd_wr_allchans(ppd, 13, (le2 << 7), BMASK(9, 7)); ibsd_wr_allchans(ppd, 13, (le2 << 7), BMASK(9, 7));
/*
* We always change parameteters, since we can choose
* values for cables without eeproms, and the cable may have
* changed from a cable with full or partial eeprom content
* to one with partial or no content.
*/
init_txdds_table(ppd, 0); init_txdds_table(ppd, 0);
/* The physical link is being re-enabled only when the
previous state was DISABLED. This should only happen when
the cable has been physically pulled. */
if (ppd->lflags & QIBL_IB_LINK_DISABLED)
qib_set_ib_7322_lstate(ppd, 0,
QLOGIC_IB_IBCC_LINKINITCMD_SLEEP);
}
} }
/* /*
...@@ -5726,7 +5758,8 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change) ...@@ -5726,7 +5758,8 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
/* now change the IBC and serdes, overriding generic */ /* now change the IBC and serdes, overriding generic */
init_txdds_table(ppd, 1); init_txdds_table(ppd, 1);
/* Re-enable the physical state machine on mezz boards /* Re-enable the physical state machine on mezz boards
* now that the correct settings have been set. */ * now that the correct settings have been set.
* QSFP boards are handles by the QSFP event handler */
if (IS_QMH(dd) || IS_QME(dd)) if (IS_QMH(dd) || IS_QME(dd))
qib_set_ib_7322_lstate(ppd, 0, qib_set_ib_7322_lstate(ppd, 0,
QLOGIC_IB_IBCC_LINKINITCMD_SLEEP); QLOGIC_IB_IBCC_LINKINITCMD_SLEEP);
...@@ -7148,7 +7181,8 @@ static void find_best_ent(struct qib_pportdata *ppd, ...@@ -7148,7 +7181,8 @@ static void find_best_ent(struct qib_pportdata *ppd,
} }
} }
/* Lookup serdes setting by cable type and attenuation */ /* Active cables don't have attenuation so we only set SERDES
* settings to account for the attenuation of the board traces. */
if (!override && QSFP_IS_ACTIVE(qd->tech)) { if (!override && QSFP_IS_ACTIVE(qd->tech)) {
*sdr_dds = txdds_sdr + ppd->dd->board_atten; *sdr_dds = txdds_sdr + ppd->dd->board_atten;
*ddr_dds = txdds_ddr + ppd->dd->board_atten; *ddr_dds = txdds_ddr + ppd->dd->board_atten;
...@@ -7465,12 +7499,6 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd) ...@@ -7465,12 +7499,6 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd)
u32 le_val, rxcaldone; u32 le_val, rxcaldone;
int chan, chan_done = (1 << SERDES_CHANS) - 1; int chan, chan_done = (1 << SERDES_CHANS) - 1;
/*
* Initialize the Tx DDS tables. Also done every QSFP event,
* for adapters with QSFP
*/
init_txdds_table(ppd, 0);
/* Clear cmode-override, may be set from older driver */ /* Clear cmode-override, may be set from older driver */
ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 0 << 14, 1 << 14); ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 0 << 14, 1 << 14);
...@@ -7656,6 +7684,12 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd) ...@@ -7656,6 +7684,12 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd)
/* VGA output common mode */ /* VGA output common mode */
ibsd_wr_allchans(ppd, 12, (3 << 2), BMASK(3, 2)); ibsd_wr_allchans(ppd, 12, (3 << 2), BMASK(3, 2));
/*
* Initialize the Tx DDS tables. Also done every QSFP event,
* for adapters with QSFP
*/
init_txdds_table(ppd, 0);
return 0; return 0;
} }
......
...@@ -585,10 +585,6 @@ int qib_init(struct qib_devdata *dd, int reinit) ...@@ -585,10 +585,6 @@ int qib_init(struct qib_devdata *dd, int reinit)
continue; continue;
} }
/* let link come up, and enable IBC */
spin_lock_irqsave(&ppd->lflags_lock, flags);
ppd->lflags &= ~QIBL_IB_LINK_DISABLED;
spin_unlock_irqrestore(&ppd->lflags_lock, flags);
portok++; portok++;
} }
......
...@@ -273,18 +273,12 @@ int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp) ...@@ -273,18 +273,12 @@ int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp)
int ret; int ret;
int idx; int idx;
u16 cks; u16 cks;
u32 mask;
u8 peek[4]; u8 peek[4];
/* ensure sane contents on invalid reads, for cable swaps */ /* ensure sane contents on invalid reads, for cable swaps */
memset(cp, 0, sizeof(*cp)); memset(cp, 0, sizeof(*cp));
mask = QSFP_GPIO_MOD_PRS_N; if (!qib_qsfp_mod_present(ppd)) {
if (ppd->hw_pidx)
mask <<= QSFP_GPIO_PORT2_SHIFT;
ret = ppd->dd->f_gpio_mod(ppd->dd, 0, 0, 0);
if (ret & mask) {
ret = -ENODEV; ret = -ENODEV;
goto bail; goto bail;
} }
...@@ -444,6 +438,19 @@ const char * const qib_qsfp_devtech[16] = { ...@@ -444,6 +438,19 @@ const char * const qib_qsfp_devtech[16] = {
static const char *pwr_codes = "1.5W2.0W2.5W3.5W"; static const char *pwr_codes = "1.5W2.0W2.5W3.5W";
int qib_qsfp_mod_present(struct qib_pportdata *ppd)
{
u32 mask;
int ret;
mask = QSFP_GPIO_MOD_PRS_N <<
(ppd->hw_pidx * QSFP_GPIO_PORT2_SHIFT);
ret = ppd->dd->f_gpio_mod(ppd->dd, 0, 0, 0);
return !((ret & mask) >>
((ppd->hw_pidx * QSFP_GPIO_PORT2_SHIFT) + 3));
}
/* /*
* Initialize structures that control access to QSFP. Called once per port * Initialize structures that control access to QSFP. Called once per port
* on cards that support QSFP. * on cards that support QSFP.
...@@ -452,7 +459,6 @@ void qib_qsfp_init(struct qib_qsfp_data *qd, ...@@ -452,7 +459,6 @@ void qib_qsfp_init(struct qib_qsfp_data *qd,
void (*fevent)(struct work_struct *)) void (*fevent)(struct work_struct *))
{ {
u32 mask, highs; u32 mask, highs;
int pins;
struct qib_devdata *dd = qd->ppd->dd; struct qib_devdata *dd = qd->ppd->dd;
...@@ -480,8 +486,7 @@ void qib_qsfp_init(struct qib_qsfp_data *qd, ...@@ -480,8 +486,7 @@ void qib_qsfp_init(struct qib_qsfp_data *qd,
mask <<= QSFP_GPIO_PORT2_SHIFT; mask <<= QSFP_GPIO_PORT2_SHIFT;
/* Do not try to wait here. Better to let event handle it */ /* Do not try to wait here. Better to let event handle it */
pins = dd->f_gpio_mod(dd, 0, 0, 0); if (!qib_qsfp_mod_present(qd->ppd))
if (pins & mask)
goto bail; goto bail;
/* We see a module, but it may be unwise to look yet. Just schedule */ /* We see a module, but it may be unwise to look yet. Just schedule */
qd->t_insert = get_jiffies_64(); qd->t_insert = get_jiffies_64();
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#define QSFP_DEV 0xA0 #define QSFP_DEV 0xA0
#define QSFP_PWR_LAG_MSEC 2000 #define QSFP_PWR_LAG_MSEC 2000
#define QSFP_MODPRS_LAG_MSEC 20
/* /*
* Below are masks for various QSFP signals, for Port 1. * Below are masks for various QSFP signals, for Port 1.
...@@ -181,6 +182,7 @@ struct qib_qsfp_data { ...@@ -181,6 +182,7 @@ struct qib_qsfp_data {
extern int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, extern int qib_refresh_qsfp_cache(struct qib_pportdata *ppd,
struct qib_qsfp_cache *cp); struct qib_qsfp_cache *cp);
extern int qib_qsfp_mod_present(struct qib_pportdata *ppd);
extern void qib_qsfp_init(struct qib_qsfp_data *qd, extern void qib_qsfp_init(struct qib_qsfp_data *qd,
void (*fevent)(struct work_struct *)); void (*fevent)(struct work_struct *));
extern void qib_qsfp_deinit(struct qib_qsfp_data *qd); extern void qib_qsfp_deinit(struct qib_qsfp_data *qd);
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