]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ipath/ipath_intr.c
IB/ipath: Better comment for rmb() in ipath_intr()
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ipath / ipath_intr.c
index b29fe7e9b11a598686052f3797b8f0b2c1c6f3d1..4795cb895f8577100fb8126a2aaa5bc8fd59769e 100644 (file)
@@ -275,6 +275,16 @@ static char *ib_linkstate(u32 linkstate)
        return ret;
 }
 
+void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev)
+{
+       struct ib_event event;
+
+       event.device = &dd->verbs_dev->ibdev;
+       event.element.port_num = 1;
+       event.event = ev;
+       ib_dispatch_event(&event);
+}
+
 static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
                                     ipath_err_t errs, int noprint)
 {
@@ -373,6 +383,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
        dd->ipath_ibpollcnt = 0;        /* some state other than 2 or 3 */
        ipath_stats.sps_iblink++;
        if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) {
+               if (dd->ipath_flags & IPATH_LINKACTIVE)
+                       signal_ib_event(dd, IB_EVENT_PORT_ERR);
                dd->ipath_flags |= IPATH_LINKDOWN;
                dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
                                     | IPATH_LINKACTIVE |
@@ -405,7 +417,10 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
                *dd->ipath_statusp |=
                        IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
                dd->ipath_f_setextled(dd, lstate, ltstate);
+               signal_ib_event(dd, IB_EVENT_PORT_ACTIVE);
        } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) {
+               if (dd->ipath_flags & IPATH_LINKACTIVE)
+                       signal_ib_event(dd, IB_EVENT_PORT_ERR);
                /*
                 * set INIT and DOWN.  Down is checked by most of the other
                 * code, but INIT is useful to know in a few places.
@@ -418,6 +433,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
                                        | IPATH_STATUS_IB_READY);
                dd->ipath_f_setextled(dd, lstate, ltstate);
        } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) {
+               if (dd->ipath_flags & IPATH_LINKACTIVE)
+                       signal_ib_event(dd, IB_EVENT_PORT_ERR);
                dd->ipath_flags |= IPATH_LINKARMED;
                dd->ipath_flags &=
                        ~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT |
@@ -436,7 +453,7 @@ skip_ibchange:
 }
 
 static void handle_supp_msgs(struct ipath_devdata *dd,
-                            unsigned supp_msgs, char msg[512])
+                            unsigned supp_msgs, char *msg, int msgsz)
 {
        /*
         * Print the message unless it's ibc status change only, which
@@ -444,9 +461,9 @@ static void handle_supp_msgs(struct ipath_devdata *dd,
         */
        if (dd->ipath_lasterror & ~INFINIPATH_E_IBSTATUSCHANGED) {
                int iserr;
-               iserr = ipath_decode_err(msg, sizeof msg,
-                               dd->ipath_lasterror &
-                               ~INFINIPATH_E_IBSTATUSCHANGED);
+               iserr = ipath_decode_err(msg, msgsz,
+                                        dd->ipath_lasterror &
+                                        ~INFINIPATH_E_IBSTATUSCHANGED);
                if (dd->ipath_lasterror &
                        ~(INFINIPATH_E_RRCVEGRFULL |
                        INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
@@ -475,8 +492,8 @@ static void handle_supp_msgs(struct ipath_devdata *dd,
 }
 
 static unsigned handle_frequent_errors(struct ipath_devdata *dd,
-                                      ipath_err_t errs, char msg[512],
-                                      int *noprint)
+                                      ipath_err_t errs, char *msg,
+                                      int msgsz, int *noprint)
 {
        unsigned long nc;
        static unsigned long nextmsg_time;
@@ -495,7 +512,7 @@ static unsigned handle_frequent_errors(struct ipath_devdata *dd,
                                nextmsg_time = nc + HZ * 3;
                }
                else if (supp_msgs) {
-                       handle_supp_msgs(dd, supp_msgs, msg);
+                       handle_supp_msgs(dd, supp_msgs, msg, msgsz);
                        supp_msgs = 0;
                        nmsgs = 0;
                }
@@ -508,14 +525,14 @@ static unsigned handle_frequent_errors(struct ipath_devdata *dd,
 
 static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
 {
-       char msg[512];
+       char msg[128];
        u64 ignore_this_time = 0;
        int i, iserr = 0;
        int chkerrpkts = 0, noprint = 0;
        unsigned supp_msgs;
        int log_idx;
 
-       supp_msgs = handle_frequent_errors(dd, errs, msg, &noprint);
+       supp_msgs = handle_frequent_errors(dd, errs, msg, sizeof msg, &noprint);
 
        /* don't report errors that are masked */
        errs &= ~dd->ipath_maskederrs;
@@ -688,17 +705,9 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                                        chkerrpkts = 1;
                                dd->ipath_lastrcvhdrqtails[i] = tl;
                                pd->port_hdrqfull++;
-                               if (test_bit(IPATH_PORT_WAITING_OVERFLOW,
-                                            &pd->port_flag)) {
-                                       clear_bit(
-                                         IPATH_PORT_WAITING_OVERFLOW,
-                                         &pd->port_flag);
-                                       set_bit(
-                                         IPATH_PORT_WAITING_OVERFLOW,
-                                         &pd->int_flag);
-                                       wake_up_interruptible(
-                                         &pd->port_wait);
-                               }
+                               /* flush hdrqfull so that poll() sees it */
+                               wmb();
+                               wake_up_interruptible(&pd->port_wait);
                        }
                }
        }
@@ -786,6 +795,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
 {
        int i, im;
        __le64 val;
+       unsigned long flags;
 
        /* disable error interrupts, to avoid confusion */
        ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
@@ -804,11 +814,14 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
                         dd->ipath_control);
 
        /* ensure pio avail updates continue */
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
                 dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
        ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                dd->ipath_sendctrl);
+                        dd->ipath_sendctrl);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
        /*
         * We just enabled pioavailupdate, so dma copy is almost certainly
@@ -840,7 +853,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
 
 /* this is separate to allow for better optimization of ipath_intr() */
 
-static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
+static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp)
 {
        /*
         * sometimes happen during driver init and unload, don't want
@@ -883,7 +896,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
                          "ignoring\n");
 }
 
-static void ipath_bad_regread(struct ipath_devdata *dd)
+static noinline void ipath_bad_regread(struct ipath_devdata *dd)
 {
        static int allbits;
 
@@ -911,31 +924,9 @@ static void ipath_bad_regread(struct ipath_devdata *dd)
        }
 }
 
-static void handle_port_pioavail(struct ipath_devdata *dd)
-{
-       u32 i;
-       /*
-        * start from port 1, since for now port 0  is never using
-        * wait_event for PIO
-        */
-       for (i = 1; dd->ipath_portpiowait && i < dd->ipath_cfgports; i++) {
-               struct ipath_portdata *pd = dd->ipath_pd[i];
-
-               if (pd && pd->port_cnt &&
-                   dd->ipath_portpiowait & (1U << i)) {
-                       clear_bit(i, &dd->ipath_portpiowait);
-                       if (test_bit(IPATH_PORT_WAITING_PIO,
-                                    &pd->port_flag)) {
-                               clear_bit(IPATH_PORT_WAITING_PIO,
-                                         &pd->port_flag);
-                               wake_up_interruptible(&pd->port_wait);
-                       }
-               }
-       }
-}
-
 static void handle_layer_pioavail(struct ipath_devdata *dd)
 {
+       unsigned long flags;
        int ret;
 
        ret = ipath_ib_piobufavail(dd->verbs_dev);
@@ -944,9 +935,12 @@ static void handle_layer_pioavail(struct ipath_devdata *dd)
 
        return;
 set:
-       set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+       dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
        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);
 }
 
 /*
@@ -960,6 +954,16 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
        int i;
        int rcvdint = 0;
 
+       /*
+        * test_and_clear_bit(IPATH_PORT_WAITING_RCV) and
+        * test_and_clear_bit(IPATH_PORT_WAITING_URG) below
+        * would both like timely updates of the bits so that
+        * we don't pass them by unnecessarily.  the rmb()
+        * here ensures that we see them promptly -- the
+        * corresponding wmb()'s are in ipath_poll_urgent()
+        * and ipath_poll_next()...
+        */
+       rmb();
        portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
                 dd->ipath_i_rcvavail_mask)
                | ((istat >> INFINIPATH_I_RCVURG_SHIFT) &
@@ -967,22 +971,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
        for (i = 1; i < dd->ipath_cfgports; i++) {
                struct ipath_portdata *pd = dd->ipath_pd[i];
                if (portr & (1 << i) && pd && pd->port_cnt) {
-                       if (test_bit(IPATH_PORT_WAITING_RCV,
-                                    &pd->port_flag)) {
-                               clear_bit(IPATH_PORT_WAITING_RCV,
-                                         &pd->port_flag);
-                               set_bit(IPATH_PORT_WAITING_RCV,
-                                       &pd->int_flag);
+                       if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
+                                              &pd->port_flag)) {
                                clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
                                          &dd->ipath_rcvctrl);
                                wake_up_interruptible(&pd->port_wait);
                                rcvdint = 1;
-                       } else if (test_bit(IPATH_PORT_WAITING_URG,
-                                           &pd->port_flag)) {
-                               clear_bit(IPATH_PORT_WAITING_URG,
-                                         &pd->port_flag);
-                               set_bit(IPATH_PORT_WAITING_URG,
-                                       &pd->int_flag);
+                       } else if (test_and_clear_bit(IPATH_PORT_WAITING_URG,
+                                                     &pd->port_flag)) {
+                               pd->port_urgent++;
                                wake_up_interruptible(&pd->port_wait);
                        }
                }
@@ -1085,8 +1082,8 @@ irqreturn_t ipath_intr(int irq, void *data)
                 * GPIO_2 indicates (on some HT4xx boards) that a packet
                 *        has arrived for Port 0. Checking for this
                 *        is controlled by flag IPATH_GPIO_INTR.
-                * GPIO_3..5 on IBA6120 Rev2 chips indicate errors
-                *        that we need to count. Checking for this
+                * GPIO_3..5 on IBA6120 Rev2 and IBA6110 Rev4 chips indicate
+                *        errors that we need to count. Checking for this
                 *        is controlled by flag IPATH_GPIO_ERRINTRS.
                 */
                u32 gpiostatus;
@@ -1137,10 +1134,8 @@ irqreturn_t ipath_intr(int irq, void *data)
                        /*
                         * Some unexpected bits remain. If they could have
                         * caused the interrupt, complain and clear.
-                        * MEA: this is almost certainly non-ideal.
-                        * we should look into auto-disable of unexpected
-                        * GPIO interrupts, possibly on a "three strikes"
-                        * basis.
+                        * To avoid repetition of this condition, also clear
+                        * the mask. It is almost certainly due to error.
                         */
                        const u32 mask = (u32) dd->ipath_gpio_mask;
 
@@ -1148,6 +1143,10 @@ irqreturn_t ipath_intr(int irq, void *data)
                                ipath_dbg("Unexpected GPIO IRQ bits %x\n",
                                  gpiostatus & mask);
                                to_clear |= (gpiostatus & mask);
+                               dd->ipath_gpio_mask &= ~(gpiostatus & mask);
+                               ipath_write_kreg(dd,
+                                       dd->ipath_kregs->kr_gpio_mask,
+                                       dd->ipath_gpio_mask);
                        }
                }
                if (to_clear) {
@@ -1185,12 +1184,14 @@ irqreturn_t ipath_intr(int irq, void *data)
                handle_urcv(dd, istat);
 
        if (istat & INFINIPATH_I_SPIOBUFAVAIL) {
-               clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+               unsigned long flags;
+
+               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+               dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL;
                ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
                                 dd->ipath_sendctrl);
-
-               if (dd->ipath_portpiowait)
-                       handle_port_pioavail(dd);
+               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
                handle_layer_pioavail(dd);
        }