Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[pandora-kernel.git] / drivers / infiniband / hw / qib / qib_iba7322.c
index 584d443..50cceb3 100644 (file)
@@ -71,6 +71,9 @@ static void qib_7322_mini_pcs_reset(struct qib_pportdata *);
 
 static u32 ahb_mod(struct qib_devdata *, int, int, int, u32, u32);
 static void ibsd_wr_allchans(struct qib_pportdata *, int, unsigned, unsigned);
+static void serdes_7322_los_enable(struct qib_pportdata *, int);
+static int serdes_7322_init_old(struct qib_pportdata *);
+static int serdes_7322_init_new(struct qib_pportdata *);
 
 #define BMASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb))
 
@@ -111,6 +114,21 @@ static ushort qib_singleport;
 module_param_named(singleport, qib_singleport, ushort, S_IRUGO);
 MODULE_PARM_DESC(singleport, "Use only IB port 1; more per-port buffer space");
 
+/*
+ * Receive header queue sizes
+ */
+static unsigned qib_rcvhdrcnt;
+module_param_named(rcvhdrcnt, qib_rcvhdrcnt, uint, S_IRUGO);
+MODULE_PARM_DESC(rcvhdrcnt, "receive header count");
+
+static unsigned qib_rcvhdrsize;
+module_param_named(rcvhdrsize, qib_rcvhdrsize, uint, S_IRUGO);
+MODULE_PARM_DESC(rcvhdrsize, "receive header size in 32-bit words");
+
+static unsigned qib_rcvhdrentsize;
+module_param_named(rcvhdrentsize, qib_rcvhdrentsize, uint, S_IRUGO);
+MODULE_PARM_DESC(rcvhdrentsize, "receive header entry size in 32-bit words");
+
 #define MAX_ATTEN_LEN 64 /* plenty for any real system */
 /* for read back, default index is ~5m copper cable */
 static char txselect_list[MAX_ATTEN_LEN] = "10";
@@ -314,7 +332,7 @@ MODULE_PARM_DESC(txselect, \
 #define krp_serdesctrl KREG_IBPORT_IDX(IBSerdesCtrl)
 
 /*
- * Per-context kernel registers.  Acess only with qib_read_kreg_ctxt()
+ * Per-context kernel registers.  Access only with qib_read_kreg_ctxt()
  * or qib_write_kreg_ctxt()
  */
 #define krc_rcvhdraddr KREG_IDX(RcvHdrAddr0)
@@ -544,6 +562,7 @@ static void write_tx_serdes_param(struct qib_pportdata *, struct txdds_ent *);
 
 #define TXDDS_TABLE_SZ 16 /* number of entries per speed in onchip table */
 #define TXDDS_EXTRA_SZ 13 /* number of extra tx settings entries */
+#define TXDDS_MFG_SZ 2    /* number of mfg tx settings entries */
 #define SERDES_CHANS 4 /* yes, it's obvious, but one less magic number */
 
 #define H1_FORCE_VAL 8
@@ -604,6 +623,7 @@ struct qib_chippport_specific {
        u8 ibmalfusesnap;
        struct qib_qsfp_data qsfp_data;
        char epmsgbuf[192]; /* for port error interrupt msg buffer */
+       u8 bounced;
 };
 
 static struct {
@@ -1677,6 +1697,8 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst)
            (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR))) {
                force_h1(ppd);
                ppd->cpspec->qdr_reforce = 1;
+               if (!ppd->dd->cspec->r1)
+                       serdes_7322_los_enable(ppd, 0);
        } else if (ppd->cpspec->qdr_reforce &&
                (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR)) &&
                 (ibclt == IB_7322_LT_STATE_CFGENH ||
@@ -1692,18 +1714,37 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst)
              ibclt <= IB_7322_LT_STATE_SLEEPQUIET)))
                adj_tx_serdes(ppd);
 
-       if (!ppd->cpspec->qdr_dfe_on && ibclt != IB_7322_LT_STATE_LINKUP &&
-           ibclt <= IB_7322_LT_STATE_SLEEPQUIET) {
-               ppd->cpspec->qdr_dfe_on = 1;
-               ppd->cpspec->qdr_dfe_time = 0;
-               /* On link down, reenable QDR adaptation */
-               qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
-                       ppd->dd->cspec->r1 ?
-                                   QDR_STATIC_ADAPT_DOWN_R1 :
-                                   QDR_STATIC_ADAPT_DOWN);
+       if (ibclt != IB_7322_LT_STATE_LINKUP) {
+               u8 ltstate = qib_7322_phys_portstate(ibcst);
+               u8 pibclt = (u8)SYM_FIELD(ppd->lastibcstat, IBCStatusA_0,
+                                         LinkTrainingState);
+               if (!ppd->dd->cspec->r1 &&
+                   pibclt == IB_7322_LT_STATE_LINKUP &&
+                   ltstate != IB_PHYSPORTSTATE_LINK_ERR_RECOVER &&
+                   ltstate != IB_PHYSPORTSTATE_RECOVERY_RETRAIN &&
+                   ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT &&
+                   ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE)
+                       /* If the link went down (but no into recovery,
+                        * turn LOS back on */
+                       serdes_7322_los_enable(ppd, 1);
+               if (!ppd->cpspec->qdr_dfe_on &&
+                   ibclt <= IB_7322_LT_STATE_SLEEPQUIET) {
+                       ppd->cpspec->qdr_dfe_on = 1;
+                       ppd->cpspec->qdr_dfe_time = 0;
+                       /* On link down, reenable QDR adaptation */
+                       qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
+                                           ppd->dd->cspec->r1 ?
+                                           QDR_STATIC_ADAPT_DOWN_R1 :
+                                           QDR_STATIC_ADAPT_DOWN);
+                       printk(KERN_INFO QIB_DRV_NAME
+                               " IB%u:%u re-enabled QDR adaptation "
+                               "ibclt %x\n", ppd->dd->unit, ppd->port, ibclt);
+               }
        }
 }
 
+static int qib_7322_set_ib_cfg(struct qib_pportdata *, int, u32);
+
 /*
  * This is per-pport error handling.
  * will likely get it's own MSIx interrupt (one for each port,
@@ -1840,7 +1881,23 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
                    IB_PHYSPORTSTATE_DISABLED)
                        qib_set_ib_7322_lstate(ppd, 0,
                               QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
-               else
+               else {
+                       u32 lstate;
+                       /*
+                        * We need the current logical link state before
+                        * lflags are set in handle_e_ibstatuschanged.
+                        */
+                       lstate = qib_7322_iblink_state(ibcs);
+
+                       if (IS_QMH(dd) && !ppd->cpspec->bounced &&
+                           ltstate == IB_PHYSPORTSTATE_LINKUP &&
+                           (lstate >= IB_PORT_INIT &&
+                               lstate <= IB_PORT_ACTIVE)) {
+                               ppd->cpspec->bounced = 1;
+                               qib_7322_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
+                                       IB_LINKCMD_DOWN | IB_LINKINITCMD_POLL);
+                       }
+
                        /*
                         * Since going into a recovery state causes the link
                         * state to go down and since recovery is transitory,
@@ -1854,6 +1911,7 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
                            ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT &&
                            ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE)
                                qib_handle_e_ibstatuschanged(ppd, ibcs);
+               }
        }
        if (*msg && iserr)
                qib_dev_porterr(dd, ppd->port, "%s error\n", msg);
@@ -2348,10 +2406,9 @@ static void qib_7322_mini_quiet_serdes(struct qib_pportdata *ppd)
        ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG;
        spin_unlock_irqrestore(&ppd->lflags_lock, flags);
        wake_up(&ppd->cpspec->autoneg_wait);
-       cancel_delayed_work(&ppd->cpspec->autoneg_work);
+       cancel_delayed_work_sync(&ppd->cpspec->autoneg_work);
        if (ppd->dd->cspec->r1)
-               cancel_delayed_work(&ppd->cpspec->ipg_work);
-       flush_scheduled_work();
+               cancel_delayed_work_sync(&ppd->cpspec->ipg_work);
 
        ppd->cpspec->chase_end = 0;
        if (ppd->cpspec->chase_timer.data) /* if initted */
@@ -2648,7 +2705,7 @@ static noinline void unknown_7322_gpio_intr(struct qib_devdata *dd)
                        if (!(pins & mask)) {
                                ++handled;
                                qd->t_insert = get_jiffies_64();
-                               schedule_work(&qd->work);
+                               queue_work(ib_wq, &qd->work);
                        }
                }
        }
@@ -2785,7 +2842,6 @@ static irqreturn_t qib_7322intr(int irq, void *data)
                                ctxtrbits &= ~rmask;
                                if (dd->rcd[i]) {
                                        qib_kreceive(dd->rcd[i], NULL, &npkts);
-                                       adjust_rcv_timeout(dd->rcd[i], npkts);
                                }
                        }
                        rmask <<= 1;
@@ -2835,7 +2891,6 @@ static irqreturn_t qib_7322pintr(int irq, void *data)
                       (1ULL << QIB_I_RCVURG_LSB)) << rcd->ctxt);
 
        qib_kreceive(rcd, NULL, &npkts);
-       adjust_rcv_timeout(rcd, npkts);
 
        return IRQ_HANDLED;
 }
@@ -3157,6 +3212,10 @@ static unsigned qib_7322_boardname(struct qib_devdata *dd)
        case BOARD_QME7342:
                n = "InfiniPath_QME7342";
                break;
+       case 8:
+               n = "InfiniPath_QME7362";
+               dd->flags |= QIB_HAS_QSFP;
+               break;
        case 15:
                n = "InfiniPath_QLE7342_TEST";
                dd->flags |= QIB_HAS_QSFP;
@@ -3475,11 +3534,6 @@ static void qib_7322_config_ctxts(struct qib_devdata *dd)
        nchipctxts = qib_read_kreg32(dd, kr_contextcnt);
        dd->cspec->numctxts = nchipctxts;
        if (qib_n_krcv_queues > 1 && dd->num_pports) {
-               /*
-                * Set the mask for which bits from the QPN are used
-                * to select a context number.
-                */
-               dd->qpn_mask = 0x3f;
                dd->first_user_ctxt = NUM_IB_PORTS +
                        (qib_n_krcv_queues - 1) * dd->num_pports;
                if (dd->first_user_ctxt > nchipctxts)
@@ -3530,8 +3584,11 @@ static void qib_7322_config_ctxts(struct qib_devdata *dd)
 
        /* kr_rcvegrcnt changes based on the number of contexts enabled */
        dd->cspec->rcvegrcnt = qib_read_kreg32(dd, kr_rcvegrcnt);
-       dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt,
-                               dd->num_pports > 1 ? 1024U : 2048U);
+       if (qib_rcvhdrcnt)
+               dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt, qib_rcvhdrcnt);
+       else
+               dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt,
+                                   dd->num_pports > 1 ? 1024U : 2048U);
 }
 
 static int qib_7322_get_ib_cfg(struct qib_pportdata *ppd, int which)
@@ -4002,8 +4059,14 @@ static int qib_7322_set_ib_table(struct qib_pportdata *ppd, int which, void *t)
 }
 
 static void qib_update_7322_usrhead(struct qib_ctxtdata *rcd, u64 hd,
-                                   u32 updegr, u32 egrhd)
+                                   u32 updegr, u32 egrhd, u32 npkts)
 {
+       /*
+        * Need to write timeout register before updating rcvhdrhead to ensure
+        * that the timer is enabled on reception of a packet.
+        */
+       if (hd >> IBA7322_HDRHEAD_PKTINT_SHIFT)
+               adjust_rcv_timeout(rcd, npkts);
        qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
        qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
        if (updegr)
@@ -4926,8 +4989,8 @@ static void try_7322_autoneg(struct qib_pportdata *ppd)
        set_7322_ibspeed_fast(ppd, QIB_IB_DDR);
        qib_7322_mini_pcs_reset(ppd);
        /* 2 msec is minimum length of a poll cycle */
-       schedule_delayed_work(&ppd->cpspec->autoneg_work,
-                             msecs_to_jiffies(2));
+       queue_delayed_work(ib_wq, &ppd->cpspec->autoneg_work,
+                          msecs_to_jiffies(2));
 }
 
 /*
@@ -5057,7 +5120,8 @@ static void try_7322_ipg(struct qib_pportdata *ppd)
                ib_free_send_mad(send_buf);
 retry:
        delay = 2 << ppd->cpspec->ipg_tries;
-       schedule_delayed_work(&ppd->cpspec->ipg_work, msecs_to_jiffies(delay));
+       queue_delayed_work(ib_wq, &ppd->cpspec->ipg_work,
+                          msecs_to_jiffies(delay));
 }
 
 /*
@@ -5522,7 +5586,7 @@ static void qsfp_7322_event(struct work_struct *work)
                u64 now = get_jiffies_64();
                if (time_after64(now, pwrup))
                        break;
-               msleep(1);
+               msleep(20);
        }
        ret = qib_refresh_qsfp_cache(ppd, &qd->cache);
        /*
@@ -5579,6 +5643,7 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
        u32 pidx, unit, port, deflt, h1;
        unsigned long val;
        int any = 0, seth1;
+       int txdds_size;
 
        str = txselect_list;
 
@@ -5587,6 +5652,10 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
        for (pidx = 0; pidx < dd->num_pports; ++pidx)
                dd->pport[pidx].cpspec->no_eep = deflt;
 
+       txdds_size = TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ;
+       if (IS_QME(dd) || IS_QMH(dd))
+               txdds_size += TXDDS_MFG_SZ;
+
        while (*nxt && nxt[1]) {
                str = ++nxt;
                unit = simple_strtoul(str, &nxt, 0);
@@ -5609,7 +5678,7 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
                                ;
                        continue;
                }
-               if (val >= TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)
+               if (val >= txdds_size)
                        continue;
                seth1 = 0;
                h1 = 0; /* gcc thinks it might be used uninitted */
@@ -5661,10 +5730,11 @@ static int setup_txselect(const char *str, struct kernel_param *kp)
                return -ENOSPC;
        }
        val = simple_strtoul(str, &n, 0);
-       if (n == str || val >= (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)) {
+       if (n == str || val >= (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ +
+                               TXDDS_MFG_SZ)) {
                printk(KERN_INFO QIB_DRV_NAME
                       "txselect_values must start with a number < %d\n",
-                       TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ);
+                       TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ + TXDDS_MFG_SZ);
                return -EINVAL;
        }
        strcpy(txselect_list, str);
@@ -5810,7 +5880,8 @@ static void write_7322_initregs(struct qib_devdata *dd)
                unsigned n, regno;
                unsigned long flags;
 
-               if (!dd->qpn_mask || !dd->pport[pidx].link_speed_supported)
+               if (dd->n_krcv_queues < 2 ||
+                       !dd->pport[pidx].link_speed_supported)
                        continue;
 
                ppd = &dd->pport[pidx];
@@ -6097,8 +6168,10 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
                ppd++;
        }
 
-       dd->rcvhdrentsize = QIB_RCVHDR_ENTSIZE;
-       dd->rcvhdrsize = QIB_DFLT_RCVHDRSIZE;
+       dd->rcvhdrentsize = qib_rcvhdrentsize ?
+               qib_rcvhdrentsize : QIB_RCVHDR_ENTSIZE;
+       dd->rcvhdrsize = qib_rcvhdrsize ?
+               qib_rcvhdrsize : QIB_DFLT_RCVHDRSIZE;
        dd->rhf_offset = dd->rcvhdrentsize - sizeof(u64) / sizeof(u32);
 
        /* we always allocate at least 2048 bytes for eager buffers */
@@ -6495,7 +6568,7 @@ static void qib_7322_txchk_change(struct qib_devdata *dd, u32 start,
                /* make sure we see an updated copy next time around */
                sendctrl_7322_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
                sleeps++;
-               msleep(1);
+               msleep(20);
        }
 
        switch (which) {
@@ -6993,6 +7066,12 @@ static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = {
        {  0, 1,  0, 12 },      /* QMH7342 backplane settings */
 };
 
+static const struct txdds_ent txdds_extra_mfg[TXDDS_MFG_SZ] = {
+       /* amp, pre, main, post */
+       { 0, 0, 0, 0 },         /* QME7342 mfg settings */
+       { 0, 0, 0, 6 },         /* QME7342 P2 mfg settings */
+};
+
 static const struct txdds_ent *get_atten_table(const struct txdds_ent *txdds,
                                               unsigned atten)
 {
@@ -7066,6 +7145,16 @@ static void find_best_ent(struct qib_pportdata *ppd,
                *sdr_dds = &txdds_extra_sdr[idx];
                *ddr_dds = &txdds_extra_ddr[idx];
                *qdr_dds = &txdds_extra_qdr[idx];
+       } else if ((IS_QME(ppd->dd) || IS_QMH(ppd->dd)) &&
+                  ppd->cpspec->no_eep < (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ +
+                                         TXDDS_MFG_SZ)) {
+               idx = ppd->cpspec->no_eep - (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ);
+               printk(KERN_INFO QIB_DRV_NAME
+                       " IB%u:%u use idx %u into txdds_mfg\n",
+                       ppd->dd->unit, ppd->port, idx);
+               *sdr_dds = &txdds_extra_mfg[idx];
+               *ddr_dds = &txdds_extra_mfg[idx];
+               *qdr_dds = &txdds_extra_mfg[idx];
        } else {
                /* this shouldn't happen, it's range checked */
                *sdr_dds = txdds_sdr + qib_long_atten;
@@ -7210,9 +7299,30 @@ static void ibsd_wr_allchans(struct qib_pportdata *ppd, int addr, unsigned data,
        }
 }
 
+static void serdes_7322_los_enable(struct qib_pportdata *ppd, int enable)
+{
+       u64 data = qib_read_kreg_port(ppd, krp_serdesctrl);
+       printk(KERN_INFO QIB_DRV_NAME " IB%u:%u Turning LOS %s\n",
+               ppd->dd->unit, ppd->port, (enable ? "on" : "off"));
+       if (enable)
+               data |= SYM_MASK(IBSerdesCtrl_0, RXLOSEN);
+       else
+               data &= ~SYM_MASK(IBSerdesCtrl_0, RXLOSEN);
+       qib_write_kreg_port(ppd, krp_serdesctrl, data);
+}
+
 static int serdes_7322_init(struct qib_pportdata *ppd)
 {
-       u64 data;
+       int ret = 0;
+       if (ppd->dd->cspec->r1)
+               ret = serdes_7322_init_old(ppd);
+       else
+               ret = serdes_7322_init_new(ppd);
+       return ret;
+}
+
+static int serdes_7322_init_old(struct qib_pportdata *ppd)
+{
        u32 le_val;
 
        /*
@@ -7270,11 +7380,7 @@ static int serdes_7322_init(struct qib_pportdata *ppd)
        ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */
        ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */
 
-       data = qib_read_kreg_port(ppd, krp_serdesctrl);
-       /* Turn off IB latency mode */
-       data &= ~SYM_MASK(IBSerdesCtrl_0, IB_LAT_MODE);
-       qib_write_kreg_port(ppd, krp_serdesctrl, data |
-               SYM_MASK(IBSerdesCtrl_0, RXLOSEN));
+       serdes_7322_los_enable(ppd, 1);
 
        /* rxbistena; set 0 to avoid effects of it switch later */
        ibsd_wr_allchans(ppd, 9, 0 << 15, 1 << 15);
@@ -7314,6 +7420,205 @@ static int serdes_7322_init(struct qib_pportdata *ppd)
        return 0;
 }
 
+static int serdes_7322_init_new(struct qib_pportdata *ppd)
+{
+       u64 tstart;
+       u32 le_val, rxcaldone;
+       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 */
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 0 << 14, 1 << 14);
+
+       /* ensure no tx overrides from earlier driver loads */
+       qib_write_kreg_port(ppd, krp_tx_deemph_override,
+               SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+               reset_tx_deemphasis_override));
+
+       /* START OF LSI SUGGESTED SERDES BRINGUP */
+       /* Reset - Calibration Setup */
+       /*       Stop DFE adaptaion */
+       ibsd_wr_allchans(ppd, 1, 0, BMASK(9, 1));
+       /*       Disable LE1 */
+       ibsd_wr_allchans(ppd, 13, 0, BMASK(5, 5));
+       /*       Disable autoadapt for LE1 */
+       ibsd_wr_allchans(ppd, 1, 0, BMASK(15, 15));
+       /*       Disable LE2 */
+       ibsd_wr_allchans(ppd, 13, 0, BMASK(6, 6));
+       /*       Disable VGA */
+       ibsd_wr_allchans(ppd, 5, 0, BMASK(0, 0));
+       /*       Disable AFE Offset Cancel */
+       ibsd_wr_allchans(ppd, 12, 0, BMASK(12, 12));
+       /*       Disable Timing Loop */
+       ibsd_wr_allchans(ppd, 2, 0, BMASK(3, 3));
+       /*       Disable Frequency Loop */
+       ibsd_wr_allchans(ppd, 2, 0, BMASK(4, 4));
+       /*       Disable Baseline Wander Correction */
+       ibsd_wr_allchans(ppd, 13, 0, BMASK(13, 13));
+       /*       Disable RX Calibration */
+       ibsd_wr_allchans(ppd, 4, 0, BMASK(10, 10));
+       /*       Disable RX Offset Calibration */
+       ibsd_wr_allchans(ppd, 12, 0, BMASK(4, 4));
+       /*       Select BB CDR */
+       ibsd_wr_allchans(ppd, 2, (1 << 15), BMASK(15, 15));
+       /*       CDR Step Size */
+       ibsd_wr_allchans(ppd, 5, 0, BMASK(9, 8));
+       /*       Enable phase Calibration */
+       ibsd_wr_allchans(ppd, 12, (1 << 5), BMASK(5, 5));
+       /*       DFE Bandwidth [2:14-12] */
+       ibsd_wr_allchans(ppd, 2, (4 << 12), BMASK(14, 12));
+       /*       DFE Config (4 taps only) */
+       ibsd_wr_allchans(ppd, 16, 0, BMASK(1, 0));
+       /*       Gain Loop Bandwidth */
+       if (!ppd->dd->cspec->r1) {
+               ibsd_wr_allchans(ppd, 12, 1 << 12, BMASK(12, 12));
+               ibsd_wr_allchans(ppd, 12, 2 << 8, BMASK(11, 8));
+       } else {
+               ibsd_wr_allchans(ppd, 19, (3 << 11), BMASK(13, 11));
+       }
+       /*       Baseline Wander Correction Gain [13:4-0] (leave as default) */
+       /*       Baseline Wander Correction Gain [3:7-5] (leave as default) */
+       /*       Data Rate Select [5:7-6] (leave as default) */
+       /*       RX Parralel Word Width [3:10-8] (leave as default) */
+
+       /* RX REST */
+       /*       Single- or Multi-channel reset */
+       /*       RX Analog reset */
+       /*       RX Digital reset */
+       ibsd_wr_allchans(ppd, 0, 0, BMASK(15, 13));
+       msleep(20);
+       /*       RX Analog reset */
+       ibsd_wr_allchans(ppd, 0, (1 << 14), BMASK(14, 14));
+       msleep(20);
+       /*       RX Digital reset */
+       ibsd_wr_allchans(ppd, 0, (1 << 13), BMASK(13, 13));
+       msleep(20);
+
+       /* setup LoS params; these are subsystem, so chan == 5 */
+       /* LoS filter threshold_count on, ch 0-3, set to 8 */
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 5, 8 << 11, BMASK(14, 11));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 8 << 4, BMASK(7, 4));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 8, 8 << 11, BMASK(14, 11));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 8 << 4, BMASK(7, 4));
+
+       /* LoS filter threshold_count off, ch 0-3, set to 4 */
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 6, 4 << 0, BMASK(3, 0));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 4 << 8, BMASK(11, 8));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 4 << 0, BMASK(3, 0));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 4 << 8, BMASK(11, 8));
+
+       /* LoS filter select enabled */
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 1 << 15, 1 << 15);
+
+       /* LoS target data:  SDR=4, DDR=2, QDR=1 */
+       ibsd_wr_allchans(ppd, 14, (1 << 3), BMASK(5, 3)); /* QDR */
+       ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */
+       ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */
+
+       /* Turn on LOS on initial SERDES init */
+       serdes_7322_los_enable(ppd, 1);
+       /* FLoop LOS gate: PPM filter  enabled */
+       ibsd_wr_allchans(ppd, 38, 0 << 10, 1 << 10);
+
+       /* RX LATCH CALIBRATION */
+       /*       Enable Eyefinder Phase Calibration latch */
+       ibsd_wr_allchans(ppd, 15, 1, BMASK(0, 0));
+       /*       Enable RX Offset Calibration latch */
+       ibsd_wr_allchans(ppd, 12, (1 << 4), BMASK(4, 4));
+       msleep(20);
+       /*       Start Calibration */
+       ibsd_wr_allchans(ppd, 4, (1 << 10), BMASK(10, 10));
+       tstart = get_jiffies_64();
+       while (chan_done &&
+              !time_after64(tstart, tstart + msecs_to_jiffies(500))) {
+               msleep(20);
+               for (chan = 0; chan < SERDES_CHANS; ++chan) {
+                       rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx),
+                                           (chan + (chan >> 1)),
+                                           25, 0, 0);
+                       if ((~rxcaldone & (u32)BMASK(9, 9)) == 0 &&
+                           (~chan_done & (1 << chan)) == 0)
+                               chan_done &= ~(1 << chan);
+               }
+       }
+       if (chan_done) {
+               printk(KERN_INFO QIB_DRV_NAME
+                        " Serdes %d calibration not done after .5 sec: 0x%x\n",
+                        IBSD(ppd->hw_pidx), chan_done);
+       } else {
+               for (chan = 0; chan < SERDES_CHANS; ++chan) {
+                       rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx),
+                                           (chan + (chan >> 1)),
+                                           25, 0, 0);
+                       if ((~rxcaldone & (u32)BMASK(10, 10)) == 0)
+                               printk(KERN_INFO QIB_DRV_NAME
+                                        " Serdes %d chan %d calibration "
+                                        "failed\n", IBSD(ppd->hw_pidx), chan);
+               }
+       }
+
+       /*       Turn off Calibration */
+       ibsd_wr_allchans(ppd, 4, 0, BMASK(10, 10));
+       msleep(20);
+
+       /* BRING RX UP */
+       /*       Set LE2 value (May be overridden in qsfp_7322_event) */
+       le_val = IS_QME(ppd->dd) ? LE2_QME : LE2_DEFAULT;
+       ibsd_wr_allchans(ppd, 13, (le_val << 7), BMASK(9, 7));
+       /*       Set LE2 Loop bandwidth */
+       ibsd_wr_allchans(ppd, 3, (7 << 5), BMASK(7, 5));
+       /*       Enable LE2 */
+       ibsd_wr_allchans(ppd, 13, (1 << 6), BMASK(6, 6));
+       msleep(20);
+       /*       Enable H0 only */
+       ibsd_wr_allchans(ppd, 1, 1, BMASK(9, 1));
+       /* gain hi stop 32 (22) (6:1) lo stop 7 (10:7) target 22 (13) (15:11) */
+       le_val = (ppd->dd->cspec->r1 || IS_QME(ppd->dd)) ? 0xb6c0 : 0x6bac;
+       ibsd_wr_allchans(ppd, 21, le_val, 0xfffe);
+       /*       Enable VGA */
+       ibsd_wr_allchans(ppd, 5, 0, BMASK(0, 0));
+       msleep(20);
+       /*       Set Frequency Loop Bandwidth */
+       ibsd_wr_allchans(ppd, 2, (7 << 5), BMASK(8, 5));
+       /*       Enable Frequency Loop */
+       ibsd_wr_allchans(ppd, 2, (1 << 4), BMASK(4, 4));
+       /*       Set Timing Loop Bandwidth */
+       ibsd_wr_allchans(ppd, 2, 0, BMASK(11, 9));
+       /*       Enable Timing Loop */
+       ibsd_wr_allchans(ppd, 2, (1 << 3), BMASK(3, 3));
+       msleep(50);
+       /*       Enable DFE
+        *       Set receive adaptation mode.  SDR and DDR adaptation are
+        *       always on, and QDR is initially enabled; later disabled.
+        */
+       qib_write_kreg_port(ppd, krp_static_adapt_dis(0), 0ULL);
+       qib_write_kreg_port(ppd, krp_static_adapt_dis(1), 0ULL);
+       qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
+                           ppd->dd->cspec->r1 ?
+                           QDR_STATIC_ADAPT_DOWN_R1 : QDR_STATIC_ADAPT_DOWN);
+       ppd->cpspec->qdr_dfe_on = 1;
+       /*       Disable LE1  */
+       ibsd_wr_allchans(ppd, 13, (0 << 5), (1 << 5));
+       /*       Disable auto adapt for LE1 */
+       ibsd_wr_allchans(ppd, 1, (0 << 15), BMASK(15, 15));
+       msleep(20);
+       /*       Enable AFE Offset Cancel */
+       ibsd_wr_allchans(ppd, 12, (1 << 12), BMASK(12, 12));
+       /*       Enable Baseline Wander Correction */
+       ibsd_wr_allchans(ppd, 12, (1 << 13), BMASK(13, 13));
+       /* Termination: rxtermctrl_r2d addr 11 bits [12:11] = 1 */
+       ibsd_wr_allchans(ppd, 11, (1 << 11), BMASK(12, 11));
+       /* VGA output common mode */
+       ibsd_wr_allchans(ppd, 12, (3 << 2), BMASK(3, 2));
+
+       return 0;
+}
+
 /* start adjust QMH serdes parameters */
 
 static void set_man_code(struct qib_pportdata *ppd, int chan, int code)