]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ipath/ipath_file_ops.c
IB/ipath: Use counters in ipath_poll and cleanup interrupts in ipath_close
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ipath / ipath_file_ops.c
index fc83f40a933fd744865b71ab935c357904e88870..016e7c4e366b0f761402d30b039948275d75b7a3 100644 (file)
@@ -1341,65 +1341,105 @@ bail:
        return ret;
 }
 
-static unsigned int ipath_poll(struct file *fp,
-                              struct poll_table_struct *pt)
+static unsigned ipath_poll_hdrqfull(struct ipath_portdata *pd)
+{
+       unsigned pollflag = 0;
+
+       if ((pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) &&
+           pd->port_hdrqfull != pd->port_hdrqfull_poll) {
+               pollflag |= POLLIN | POLLRDNORM;
+               pd->port_hdrqfull_poll = pd->port_hdrqfull;
+       }
+
+       return pollflag;
+}
+
+static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
+                                     struct file *fp,
+                                     struct poll_table_struct *pt)
 {
-       struct ipath_portdata *pd;
-       u32 head, tail;
-       int bit;
        unsigned pollflag = 0;
        struct ipath_devdata *dd;
 
-       pd = port_fp(fp);
-       if (!pd)
-               goto bail;
        dd = pd->port_dd;
 
-       bit = pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT;
-       set_bit(bit, &dd->ipath_rcvctrl);
+       /* variable access in ipath_poll_hdrqfull() needs this */
+       rmb();
+       pollflag = ipath_poll_hdrqfull(pd);
 
-       /*
-        * Before blocking, make sure that head is still == tail,
-        * reading from the chip, so we can be sure the interrupt
-        * enable has made it to the chip.  If not equal, disable
-        * interrupt again and return immediately.  This avoids races,
-        * and the overhead of the chip read doesn't matter much at
-        * this point, since we are waiting for something anyway.
-        */
+       if (pd->port_urgent != pd->port_urgent_poll) {
+               pollflag |= POLLIN | POLLRDNORM;
+               pd->port_urgent_poll = pd->port_urgent;
+       }
 
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                        dd->ipath_rcvctrl);
+       if (!pollflag) {
+               /* this saves a spin_lock/unlock in interrupt handler... */
+               set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag);
+               /* flush waiting flag so don't miss an event... */
+               wmb();
+               poll_wait(fp, &pd->port_wait, pt);
+       }
+
+       return pollflag;
+}
+
+static unsigned int ipath_poll_next(struct ipath_portdata *pd,
+                                   struct file *fp,
+                                   struct poll_table_struct *pt)
+{
+       u32 head;
+       u32 tail;
+       unsigned pollflag = 0;
+       struct ipath_devdata *dd;
+
+       dd = pd->port_dd;
+
+       /* variable access in ipath_poll_hdrqfull() needs this */
+       rmb();
+       pollflag = ipath_poll_hdrqfull(pd);
 
        head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
-       tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
+       tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
 
-       if (tail == head) {
+       if (head != tail)
+               pollflag |= POLLIN | POLLRDNORM;
+       else {
+               /* this saves a spin_lock/unlock in interrupt handler */
                set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
+               /* flush waiting flag so we don't miss an event */
+               wmb();
+
+               set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+                       &dd->ipath_rcvctrl);
+
+               ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+                                dd->ipath_rcvctrl);
+
                if (dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
-                       (void)ipath_write_ureg(dd, ur_rcvhdrhead,
-                                              dd->ipath_rhdrhead_intr_off
-                                              | head, pd->port_port);
-               poll_wait(fp, &pd->port_wait, pt);
+                       ipath_write_ureg(dd, ur_rcvhdrhead,
+                                        dd->ipath_rhdrhead_intr_off | head,
+                                        pd->port_port);
 
-               if (test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) {
-                       /* timed out, no packets received */
-                       clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
-                       pd->port_rcvwait_to++;
-               }
-               else
-                       pollflag = POLLIN | POLLRDNORM;
-       }
-       else {
-               /* it's already happened; don't do wait_event overhead */
-               pollflag = POLLIN | POLLRDNORM;
-               pd->port_rcvnowait++;
+               poll_wait(fp, &pd->port_wait, pt);
        }
 
-       clear_bit(bit, &dd->ipath_rcvctrl);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                        dd->ipath_rcvctrl);
+       return pollflag;
+}
+
+static unsigned int ipath_poll(struct file *fp,
+                              struct poll_table_struct *pt)
+{
+       struct ipath_portdata *pd;
+       unsigned pollflag;
+
+       pd = port_fp(fp);
+       if (!pd)
+               pollflag = 0;
+       else if (pd->poll_type & IPATH_POLL_TYPE_URGENT)
+               pollflag = ipath_poll_urgent(pd, fp, pt);
+       else
+               pollflag = ipath_poll_next(pd, fp, pt);
 
-bail:
        return pollflag;
 }
 
@@ -1444,10 +1484,10 @@ static int init_subports(struct ipath_devdata *dd,
        size_t size;
 
        /*
-        * If the user is requesting zero or one port,
+        * If the user is requesting zero subports,
         * skip the subport allocation.
         */
-       if (uinfo->spu_subport_cnt <= 1)
+       if (uinfo->spu_subport_cnt <= 0)
                goto bail;
 
        /* Self-consistency check for ipath_compatible_subports() */
@@ -1884,6 +1924,12 @@ static int ipath_do_user_init(struct file *fp,
        ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
                pd->port_port, head32);
        pd->port_tidcursor = 0; /* start at beginning after open */
+
+       /* initialize poll variables... */
+       pd->port_urgent = 0;
+       pd->port_urgent_poll = 0;
+       pd->port_hdrqfull_poll = pd->port_hdrqfull;
+
        /*
         * now enable the port; the tail registers will be written to memory
         * by the chip as soon as it sees the write to
@@ -2006,9 +2052,11 @@ static int ipath_close(struct inode *in, struct file *fp)
 
        if (dd->ipath_kregbase) {
                int i;
-               /* atomically clear receive enable port. */
+               /* atomically clear receive enable port and intr avail. */
                clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
                          &dd->ipath_rcvctrl);
+               clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+                         &dd->ipath_rcvctrl);
                ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
                        dd->ipath_rcvctrl);
                /* and read back from chip to be sure that nothing
@@ -2173,6 +2221,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
                src = NULL;
                dest = NULL;
                break;
+       case IPATH_CMD_POLL_TYPE:
+               copy = sizeof(cmd.cmd.poll_type);
+               dest = &cmd.cmd.poll_type;
+               src = &ucmd->cmd.poll_type;
+               break;
        default:
                ret = -EINVAL;
                goto bail;
@@ -2245,6 +2298,9 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
        case IPATH_CMD_PIOAVAILUPD:
                ret = ipath_force_pio_avail_update(pd->port_dd);
                break;
+       case IPATH_CMD_POLL_TYPE:
+               pd->poll_type = cmd.cmd.poll_type;
+               break;
        }
 
        if (ret >= 0)