aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorMike Marciniszyn <mike.marciniszyn@qlogic.com>2011-01-10 20:42:20 -0500
committerRoland Dreier <rolandd@cisco.com>2011-01-10 20:42:20 -0500
commita0a234d47dcacfdb0a8dfcb861e0bd8300702674 (patch)
tree2be8f11631c7f1c61a78b38c74348c73e7dd891c /drivers/infiniband
parent16028f27778cb6439516c36c0a72446d29805691 (diff)
IB/qib: New SERDES init routine and improvements to SI quality
Implement new SERDES initialization routine and improvements to signal integrity -- disable LE1 adaptation, disable LOS after link-up, set better SERDES parameters. Signed-off-by: Mike Marciniszyn <mike.marciniszyn@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c270
1 files changed, 255 insertions, 15 deletions
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 40f4a2353320..d23297a307aa 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -71,6 +71,9 @@ static void qib_7322_mini_pcs_reset(struct qib_pportdata *);
71 71
72static u32 ahb_mod(struct qib_devdata *, int, int, int, u32, u32); 72static u32 ahb_mod(struct qib_devdata *, int, int, int, u32, u32);
73static void ibsd_wr_allchans(struct qib_pportdata *, int, unsigned, unsigned); 73static void ibsd_wr_allchans(struct qib_pportdata *, int, unsigned, unsigned);
74static void serdes_7322_los_enable(struct qib_pportdata *, int);
75static int serdes_7322_init_old(struct qib_pportdata *);
76static int serdes_7322_init_new(struct qib_pportdata *);
74 77
75#define BMASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb)) 78#define BMASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb))
76 79
@@ -1692,6 +1695,8 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst)
1692 (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR))) { 1695 (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR))) {
1693 force_h1(ppd); 1696 force_h1(ppd);
1694 ppd->cpspec->qdr_reforce = 1; 1697 ppd->cpspec->qdr_reforce = 1;
1698 if (!ppd->dd->cspec->r1)
1699 serdes_7322_los_enable(ppd, 0);
1695 } else if (ppd->cpspec->qdr_reforce && 1700 } else if (ppd->cpspec->qdr_reforce &&
1696 (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR)) && 1701 (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR)) &&
1697 (ibclt == IB_7322_LT_STATE_CFGENH || 1702 (ibclt == IB_7322_LT_STATE_CFGENH ||
@@ -1707,15 +1712,32 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst)
1707 ibclt <= IB_7322_LT_STATE_SLEEPQUIET))) 1712 ibclt <= IB_7322_LT_STATE_SLEEPQUIET)))
1708 adj_tx_serdes(ppd); 1713 adj_tx_serdes(ppd);
1709 1714
1710 if (!ppd->cpspec->qdr_dfe_on && ibclt != IB_7322_LT_STATE_LINKUP && 1715 if (ibclt != IB_7322_LT_STATE_LINKUP) {
1711 ibclt <= IB_7322_LT_STATE_SLEEPQUIET) { 1716 u8 ltstate = qib_7322_phys_portstate(ibcst);
1712 ppd->cpspec->qdr_dfe_on = 1; 1717 u8 pibclt = (u8)SYM_FIELD(ppd->lastibcstat, IBCStatusA_0,
1713 ppd->cpspec->qdr_dfe_time = 0; 1718 LinkTrainingState);
1714 /* On link down, reenable QDR adaptation */ 1719 if (!ppd->dd->cspec->r1 &&
1715 qib_write_kreg_port(ppd, krp_static_adapt_dis(2), 1720 pibclt == IB_7322_LT_STATE_LINKUP &&
1716 ppd->dd->cspec->r1 ? 1721 ltstate != IB_PHYSPORTSTATE_LINK_ERR_RECOVER &&
1717 QDR_STATIC_ADAPT_DOWN_R1 : 1722 ltstate != IB_PHYSPORTSTATE_RECOVERY_RETRAIN &&
1718 QDR_STATIC_ADAPT_DOWN); 1723 ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT &&
1724 ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE)
1725 /* If the link went down (but no into recovery,
1726 * turn LOS back on */
1727 serdes_7322_los_enable(ppd, 1);
1728 if (!ppd->cpspec->qdr_dfe_on &&
1729 ibclt <= IB_7322_LT_STATE_SLEEPQUIET) {
1730 ppd->cpspec->qdr_dfe_on = 1;
1731 ppd->cpspec->qdr_dfe_time = 0;
1732 /* On link down, reenable QDR adaptation */
1733 qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
1734 ppd->dd->cspec->r1 ?
1735 QDR_STATIC_ADAPT_DOWN_R1 :
1736 QDR_STATIC_ADAPT_DOWN);
1737 printk(KERN_INFO QIB_DRV_NAME
1738 " IB%u:%u re-enabled QDR adaptation "
1739 "ibclt %x\n", ppd->dd->unit, ppd->port, ibclt);
1740 }
1719 } 1741 }
1720} 1742}
1721 1743
@@ -5544,7 +5566,7 @@ static void qsfp_7322_event(struct work_struct *work)
5544 u64 now = get_jiffies_64(); 5566 u64 now = get_jiffies_64();
5545 if (time_after64(now, pwrup)) 5567 if (time_after64(now, pwrup))
5546 break; 5568 break;
5547 msleep(1); 5569 msleep(20);
5548 } 5570 }
5549 ret = qib_refresh_qsfp_cache(ppd, &qd->cache); 5571 ret = qib_refresh_qsfp_cache(ppd, &qd->cache);
5550 /* 5572 /*
@@ -6519,7 +6541,7 @@ static void qib_7322_txchk_change(struct qib_devdata *dd, u32 start,
6519 /* make sure we see an updated copy next time around */ 6541 /* make sure we see an updated copy next time around */
6520 sendctrl_7322_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP); 6542 sendctrl_7322_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
6521 sleeps++; 6543 sleeps++;
6522 msleep(1); 6544 msleep(20);
6523 } 6545 }
6524 6546
6525 switch (which) { 6547 switch (which) {
@@ -7234,9 +7256,30 @@ static void ibsd_wr_allchans(struct qib_pportdata *ppd, int addr, unsigned data,
7234 } 7256 }
7235} 7257}
7236 7258
7259static void serdes_7322_los_enable(struct qib_pportdata *ppd, int enable)
7260{
7261 u64 data = qib_read_kreg_port(ppd, krp_serdesctrl);
7262 printk(KERN_INFO QIB_DRV_NAME " Turning LOS %s for port %d\n",
7263 (enable ? "on" : "off"), ppd->port);
7264 if (enable)
7265 data |= SYM_MASK(IBSerdesCtrl_0, RXLOSEN);
7266 else
7267 data &= ~SYM_MASK(IBSerdesCtrl_0, RXLOSEN);
7268 qib_write_kreg_port(ppd, krp_serdesctrl, data);
7269}
7270
7237static int serdes_7322_init(struct qib_pportdata *ppd) 7271static int serdes_7322_init(struct qib_pportdata *ppd)
7238{ 7272{
7239 u64 data; 7273 int ret = 0;
7274 if (ppd->dd->cspec->r1)
7275 ret = serdes_7322_init_old(ppd);
7276 else
7277 ret = serdes_7322_init_new(ppd);
7278 return ret;
7279}
7280
7281static int serdes_7322_init_old(struct qib_pportdata *ppd)
7282{
7240 u32 le_val; 7283 u32 le_val;
7241 7284
7242 /* 7285 /*
@@ -7294,9 +7337,7 @@ static int serdes_7322_init(struct qib_pportdata *ppd)
7294 ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */ 7337 ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */
7295 ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */ 7338 ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */
7296 7339
7297 data = qib_read_kreg_port(ppd, krp_serdesctrl); 7340 serdes_7322_los_enable(ppd, 1);
7298 qib_write_kreg_port(ppd, krp_serdesctrl, data |
7299 SYM_MASK(IBSerdesCtrl_0, RXLOSEN));
7300 7341
7301 /* rxbistena; set 0 to avoid effects of it switch later */ 7342 /* rxbistena; set 0 to avoid effects of it switch later */
7302 ibsd_wr_allchans(ppd, 9, 0 << 15, 1 << 15); 7343 ibsd_wr_allchans(ppd, 9, 0 << 15, 1 << 15);
@@ -7336,6 +7377,205 @@ static int serdes_7322_init(struct qib_pportdata *ppd)
7336 return 0; 7377 return 0;
7337} 7378}
7338 7379
7380static int serdes_7322_init_new(struct qib_pportdata *ppd)
7381{
7382 u64 tstart;
7383 u32 le_val, rxcaldone;
7384 int chan, chan_done = (1 << SERDES_CHANS) - 1;
7385
7386 /*
7387 * Initialize the Tx DDS tables. Also done every QSFP event,
7388 * for adapters with QSFP
7389 */
7390 init_txdds_table(ppd, 0);
7391
7392 /* Clear cmode-override, may be set from older driver */
7393 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 0 << 14, 1 << 14);
7394
7395 /* ensure no tx overrides from earlier driver loads */
7396 qib_write_kreg_port(ppd, krp_tx_deemph_override,
7397 SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
7398 reset_tx_deemphasis_override));
7399
7400 /* START OF LSI SUGGESTED SERDES BRINGUP */
7401 /* Reset - Calibration Setup */
7402 /* Stop DFE adaptaion */
7403 ibsd_wr_allchans(ppd, 1, 0, BMASK(9, 1));
7404 /* Disable LE1 */
7405 ibsd_wr_allchans(ppd, 13, 0, BMASK(5, 5));
7406 /* Disable autoadapt for LE1 */
7407 ibsd_wr_allchans(ppd, 1, 0, BMASK(15, 15));
7408 /* Disable LE2 */
7409 ibsd_wr_allchans(ppd, 13, 0, BMASK(6, 6));
7410 /* Disable VGA */
7411 ibsd_wr_allchans(ppd, 5, 0, BMASK(0, 0));
7412 /* Disable AFE Offset Cancel */
7413 ibsd_wr_allchans(ppd, 12, 0, BMASK(12, 12));
7414 /* Disable Timing Loop */
7415 ibsd_wr_allchans(ppd, 2, 0, BMASK(3, 3));
7416 /* Disable Frequency Loop */
7417 ibsd_wr_allchans(ppd, 2, 0, BMASK(4, 4));
7418 /* Disable Baseline Wander Correction */
7419 ibsd_wr_allchans(ppd, 13, 0, BMASK(13, 13));
7420 /* Disable RX Calibration */
7421 ibsd_wr_allchans(ppd, 4, 0, BMASK(10, 10));
7422 /* Disable RX Offset Calibration */
7423 ibsd_wr_allchans(ppd, 12, 0, BMASK(4, 4));
7424 /* Select BB CDR */
7425 ibsd_wr_allchans(ppd, 2, (1 << 15), BMASK(15, 15));
7426 /* CDR Step Size */
7427 ibsd_wr_allchans(ppd, 5, 0, BMASK(9, 8));
7428 /* Enable phase Calibration */
7429 ibsd_wr_allchans(ppd, 12, (1 << 5), BMASK(5, 5));
7430 /* DFE Bandwidth [2:14-12] */
7431 ibsd_wr_allchans(ppd, 2, (4 << 12), BMASK(14, 12));
7432 /* DFE Config (4 taps only) */
7433 ibsd_wr_allchans(ppd, 16, 0, BMASK(1, 0));
7434 /* Gain Loop Bandwidth */
7435 if (!ppd->dd->cspec->r1) {
7436 ibsd_wr_allchans(ppd, 12, 1 << 12, BMASK(12, 12));
7437 ibsd_wr_allchans(ppd, 12, 2 << 8, BMASK(11, 8));
7438 } else {
7439 ibsd_wr_allchans(ppd, 19, (3 << 11), BMASK(13, 11));
7440 }
7441 /* Baseline Wander Correction Gain [13:4-0] (leave as default) */
7442 /* Baseline Wander Correction Gain [3:7-5] (leave as default) */
7443 /* Data Rate Select [5:7-6] (leave as default) */
7444 /* RX Parralel Word Width [3:10-8] (leave as default) */
7445
7446 /* RX REST */
7447 /* Single- or Multi-channel reset */
7448 /* RX Analog reset */
7449 /* RX Digital reset */
7450 ibsd_wr_allchans(ppd, 0, 0, BMASK(15, 13));
7451 msleep(20);
7452 /* RX Analog reset */
7453 ibsd_wr_allchans(ppd, 0, (1 << 14), BMASK(14, 14));
7454 msleep(20);
7455 /* RX Digital reset */
7456 ibsd_wr_allchans(ppd, 0, (1 << 13), BMASK(13, 13));
7457 msleep(20);
7458
7459 /* setup LoS params; these are subsystem, so chan == 5 */
7460 /* LoS filter threshold_count on, ch 0-3, set to 8 */
7461 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 5, 8 << 11, BMASK(14, 11));
7462 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 8 << 4, BMASK(7, 4));
7463 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 8, 8 << 11, BMASK(14, 11));
7464 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 8 << 4, BMASK(7, 4));
7465
7466 /* LoS filter threshold_count off, ch 0-3, set to 4 */
7467 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 6, 4 << 0, BMASK(3, 0));
7468 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 4 << 8, BMASK(11, 8));
7469 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 4 << 0, BMASK(3, 0));
7470 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 4 << 8, BMASK(11, 8));
7471
7472 /* LoS filter select enabled */
7473 ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 1 << 15, 1 << 15);
7474
7475 /* LoS target data: SDR=4, DDR=2, QDR=1 */
7476 ibsd_wr_allchans(ppd, 14, (1 << 3), BMASK(5, 3)); /* QDR */
7477 ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */
7478 ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */
7479
7480 /* Turn on LOS on initial SERDES init */
7481 serdes_7322_los_enable(ppd, 1);
7482 /* FLoop LOS gate: PPM filter enabled */
7483 ibsd_wr_allchans(ppd, 38, 0 << 10, 1 << 10);
7484
7485 /* RX LATCH CALIBRATION */
7486 /* Enable Eyefinder Phase Calibration latch */
7487 ibsd_wr_allchans(ppd, 15, 1, BMASK(0, 0));
7488 /* Enable RX Offset Calibration latch */
7489 ibsd_wr_allchans(ppd, 12, (1 << 4), BMASK(4, 4));
7490 msleep(20);
7491 /* Start Calibration */
7492 ibsd_wr_allchans(ppd, 4, (1 << 10), BMASK(10, 10));
7493 tstart = get_jiffies_64();
7494 while (chan_done &&
7495 !time_after64(tstart, tstart + msecs_to_jiffies(500))) {
7496 msleep(20);
7497 for (chan = 0; chan < SERDES_CHANS; ++chan) {
7498 rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx),
7499 (chan + (chan >> 1)),
7500 25, 0, 0);
7501 if ((~rxcaldone & (u32)BMASK(9, 9)) == 0 &&
7502 (~chan_done & (1 << chan)) == 0)
7503 chan_done &= ~(1 << chan);
7504 }
7505 }
7506 if (chan_done) {
7507 printk(KERN_INFO QIB_DRV_NAME
7508 " Serdes %d calibration not done after .5 sec: 0x%x\n",
7509 IBSD(ppd->hw_pidx), chan_done);
7510 } else {
7511 for (chan = 0; chan < SERDES_CHANS; ++chan) {
7512 rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx),
7513 (chan + (chan >> 1)),
7514 25, 0, 0);
7515 if ((~rxcaldone & (u32)BMASK(10, 10)) == 0)
7516 printk(KERN_INFO QIB_DRV_NAME
7517 " Serdes %d chan %d calibration "
7518 "failed\n", IBSD(ppd->hw_pidx), chan);
7519 }
7520 }
7521
7522 /* Turn off Calibration */
7523 ibsd_wr_allchans(ppd, 4, 0, BMASK(10, 10));
7524 msleep(20);
7525
7526 /* BRING RX UP */
7527 /* Set LE2 value (May be overridden in qsfp_7322_event) */
7528 le_val = IS_QME(ppd->dd) ? LE2_QME : LE2_DEFAULT;
7529 ibsd_wr_allchans(ppd, 13, (le_val << 7), BMASK(9, 7));
7530 /* Set LE2 Loop bandwidth */
7531 ibsd_wr_allchans(ppd, 3, (7 << 5), BMASK(7, 5));
7532 /* Enable LE2 */
7533 ibsd_wr_allchans(ppd, 13, (1 << 6), BMASK(6, 6));
7534 msleep(20);
7535 /* Enable H0 only */
7536 ibsd_wr_allchans(ppd, 1, 1, BMASK(9, 1));
7537 /* gain hi stop 32 (22) (6:1) lo stop 7 (10:7) target 22 (13) (15:11) */
7538 le_val = (ppd->dd->cspec->r1 || IS_QME(ppd->dd)) ? 0xb6c0 : 0x6bac;
7539 ibsd_wr_allchans(ppd, 21, le_val, 0xfffe);
7540 /* Enable VGA */
7541 ibsd_wr_allchans(ppd, 5, 0, BMASK(0, 0));
7542 msleep(20);
7543 /* Set Frequency Loop Bandwidth */
7544 ibsd_wr_allchans(ppd, 2, (7 << 5), BMASK(8, 5));
7545 /* Enable Frequency Loop */
7546 ibsd_wr_allchans(ppd, 2, (1 << 4), BMASK(4, 4));
7547 /* Set Timing Loop Bandwidth */
7548 ibsd_wr_allchans(ppd, 2, 0, BMASK(11, 9));
7549 /* Enable Timing Loop */
7550 ibsd_wr_allchans(ppd, 2, (1 << 3), BMASK(3, 3));
7551 msleep(50);
7552 /* Enable DFE
7553 * Set receive adaptation mode. SDR and DDR adaptation are
7554 * always on, and QDR is initially enabled; later disabled.
7555 */
7556 qib_write_kreg_port(ppd, krp_static_adapt_dis(0), 0ULL);
7557 qib_write_kreg_port(ppd, krp_static_adapt_dis(1), 0ULL);
7558 qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
7559 ppd->dd->cspec->r1 ?
7560 QDR_STATIC_ADAPT_DOWN_R1 : QDR_STATIC_ADAPT_DOWN);
7561 ppd->cpspec->qdr_dfe_on = 1;
7562 /* Disable LE1 */
7563 ibsd_wr_allchans(ppd, 13, (0 << 5), (1 << 5));
7564 /* Disable auto adapt for LE1 */
7565 ibsd_wr_allchans(ppd, 1, (0 << 15), BMASK(15, 15));
7566 msleep(20);
7567 /* Enable AFE Offset Cancel */
7568 ibsd_wr_allchans(ppd, 12, (1 << 12), BMASK(12, 12));
7569 /* Enable Baseline Wander Correction */
7570 ibsd_wr_allchans(ppd, 12, (1 << 13), BMASK(13, 13));
7571 /* Termination: rxtermctrl_r2d addr 11 bits [12:11] = 1 */
7572 ibsd_wr_allchans(ppd, 11, (1 << 11), BMASK(12, 11));
7573 /* VGA output common mode */
7574 ibsd_wr_allchans(ppd, 12, (3 << 2), BMASK(3, 2));
7575
7576 return 0;
7577}
7578
7339/* start adjust QMH serdes parameters */ 7579/* start adjust QMH serdes parameters */
7340 7580
7341static void set_man_code(struct qib_pportdata *ppd, int chan, int code) 7581static void set_man_code(struct qib_pportdata *ppd, int chan, int code)