]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ipath/ipath_init_chip.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ipath / ipath_init_chip.c
index 720ff4df84ebba9331f1ecdf9816095b5192de45..27dd89476660846c723f60518828d4692206f213 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -230,6 +230,15 @@ static int init_chip_first(struct ipath_devdata *dd)
        int ret = 0;
        u64 val;
 
+       spin_lock_init(&dd->ipath_kernel_tid_lock);
+       spin_lock_init(&dd->ipath_user_tid_lock);
+       spin_lock_init(&dd->ipath_sendctrl_lock);
+       spin_lock_init(&dd->ipath_sdma_lock);
+       spin_lock_init(&dd->ipath_gpio_lock);
+       spin_lock_init(&dd->ipath_eep_st_lock);
+       spin_lock_init(&dd->ipath_sdepb_lock);
+       mutex_init(&dd->ipath_eep_lock);
+
        /*
         * skip cfgports stuff because we are not allocating memory,
         * and we don't want problems if the portcnt changed due to
@@ -319,12 +328,6 @@ static int init_chip_first(struct ipath_devdata *dd)
        else ipath_dbg("%u 2k piobufs @ %p\n",
                       dd->ipath_piobcnt2k, dd->ipath_pio2kbase);
 
-       spin_lock_init(&dd->ipath_tid_lock);
-       spin_lock_init(&dd->ipath_sendctrl_lock);
-       spin_lock_init(&dd->ipath_gpio_lock);
-       spin_lock_init(&dd->ipath_eep_st_lock);
-       mutex_init(&dd->ipath_eep_lock);
-
 done:
        return ret;
 }
@@ -341,6 +344,7 @@ static int init_chip_reset(struct ipath_devdata *dd)
 {
        u32 rtmp;
        int i;
+       unsigned long flags;
 
        /*
         * ensure chip does no sends or receives, tail updates, or
@@ -356,8 +360,13 @@ static int init_chip_reset(struct ipath_devdata *dd)
        ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
                dd->ipath_rcvctrl);
 
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+       dd->ipath_sendctrl = 0U; /* no sdma, etc */
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control, dd->ipath_control);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
 
        rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt);
        if (rtmp != dd->ipath_rcvtidcnt)
@@ -478,6 +487,14 @@ static void enable_chip(struct ipath_devdata *dd, int reinit)
        /* Enable PIO send, and update of PIOavail regs to memory. */
        dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE |
                INFINIPATH_S_PIOBUFAVAILUPD;
+
+       /*
+        * Set the PIO avail update threshold to host memory
+        * on chips that support it.
+        */
+       if (dd->ipath_pioupd_thresh)
+               dd->ipath_sendctrl |= dd->ipath_pioupd_thresh
+                       << INFINIPATH_S_UPDTHRESH_SHIFT;
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
        ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
        spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
@@ -539,7 +556,7 @@ static void enable_chip(struct ipath_devdata *dd, int reinit)
 
 static int init_housekeeping(struct ipath_devdata *dd, int reinit)
 {
-       char boardn[32];
+       char boardn[40];
        int ret = 0;
 
        /*
@@ -651,6 +668,28 @@ done:
        return ret;
 }
 
+static void verify_interrupt(unsigned long opaque)
+{
+       struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
+
+       if (!dd)
+               return; /* being torn down */
+
+       /*
+        * If we don't have any interrupts, let the user know and
+        * don't bother checking again.
+        */
+       if (dd->ipath_int_counter == 0) {
+               if (!dd->ipath_f_intr_fallback(dd))
+                       dev_err(&dd->pcidev->dev, "No interrupts detected, "
+                               "not usable.\n");
+               else /* re-arm the timer to see if fallback works */
+                       mod_timer(&dd->ipath_intrchk_timer, jiffies + HZ/2);
+       } else
+               ipath_cdbg(VERBOSE, "%u interrupts at timer check\n",
+                       dd->ipath_int_counter);
+}
+
 /**
  * ipath_init_chip - do the actual initialization sequence on the chip
  * @dd: the infinipath device
@@ -757,8 +796,19 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
        ipath_cdbg(VERBOSE, "%d PIO bufs for kernel out of %d total %u "
                   "each for %u user ports\n", kpiobufs,
                   piobufs, dd->ipath_pbufsport, uports);
+       if (dd->ipath_pioupd_thresh) {
+               if (dd->ipath_pbufsport < dd->ipath_pioupd_thresh)
+                       dd->ipath_pioupd_thresh = dd->ipath_pbufsport;
+               if (kpiobufs < dd->ipath_pioupd_thresh)
+                       dd->ipath_pioupd_thresh = kpiobufs;
+       }
+
+       ret = dd->ipath_f_early_init(dd);
+       if (ret) {
+               ipath_dev_err(dd, "Early initialization failure\n");
+               goto done;
+       }
 
-       dd->ipath_f_early_init(dd);
        /*
         * Cancel any possible active sends from early driver load.
         * Follows early_init because some chips have to initialize
@@ -930,6 +980,10 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
                dd->ipath_stats_timer_active = 1;
        }
 
+       /* Set up SendDMA if chip supports it */
+       if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
+               ret = setup_sdma(dd);
+
        /* Set up HoL state */
        init_timer(&dd->ipath_hol_timer);
        dd->ipath_hol_timer.function = ipath_hol_event;
@@ -948,6 +1002,20 @@ done:
                                         0ULL);
                        /* chip is usable; mark it as initialized */
                        *dd->ipath_statusp |= IPATH_STATUS_INITTED;
+
+                       /*
+                        * setup to verify we get an interrupt, and fallback
+                        * to an alternate if necessary and possible
+                        */
+                       if (!reinit) {
+                               init_timer(&dd->ipath_intrchk_timer);
+                               dd->ipath_intrchk_timer.function =
+                                       verify_interrupt;
+                               dd->ipath_intrchk_timer.data =
+                                       (unsigned long) dd;
+                       }
+                       dd->ipath_intrchk_timer.expires = jiffies + HZ/2;
+                       add_timer(&dd->ipath_intrchk_timer);
                } else
                        ipath_dev_err(dd, "No interrupts enabled, couldn't "
                                      "setup interrupt address\n");