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 d23297a..50cceb3 100644 (file)
@@ -332,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)
@@ -562,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
@@ -622,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 {
@@ -1741,6 +1743,8 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst)
        }
 }
 
+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,
@@ -1877,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,
@@ -1891,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);
@@ -2385,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 */
@@ -2685,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);
                        }
                }
        }
@@ -2822,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;
@@ -2872,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;
 }
@@ -3516,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)
@@ -4046,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)
@@ -4970,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));
 }
 
 /*
@@ -5101,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));
 }
 
 /*
@@ -5623,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;
 
@@ -5631,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);
@@ -5653,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 */
@@ -5705,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);
@@ -5854,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];
@@ -7039,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)
 {
@@ -7112,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;
@@ -7259,8 +7302,8 @@ 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 " Turning LOS %s for port %d\n",
-                (enable ? "on" : "off"), ppd->port);
+       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