]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ipath/ipath_rc.c
IB/ipath: Update copyright dates for files changed in 2008
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ipath / ipath_rc.c
index 46744ea2babdb336510b3772ed7dfd9fb6d8608c..467981905bbeb09672b2d60e89c07a5a45c3c257 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) 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -31,6 +31,8 @@
  * SOFTWARE.
  */
 
+#include <linux/io.h>
+
 #include "ipath_verbs.h"
 #include "ipath_kernel.h"
 
@@ -81,9 +83,8 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
  * Note that we are in the responder's side of the QP context.
  * Note the QP s_lock must be held.
  */
-static int ipath_make_rc_ack(struct ipath_qp *qp,
-                            struct ipath_other_headers *ohdr,
-                            u32 pmtu, u32 *bth0p, u32 *bth2p)
+static int ipath_make_rc_ack(struct ipath_ibdev *dev, struct ipath_qp *qp,
+                            struct ipath_other_headers *ohdr, u32 pmtu)
 {
        struct ipath_ack_entry *e;
        u32 hwords;
@@ -192,8 +193,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
        }
        qp->s_hdrwords = hwords;
        qp->s_cur_size = len;
-       *bth0p = bth0 | (1 << 22); /* Set M bit */
-       *bth2p = bth2;
+       ipath_make_ruc_header(dev, qp, ohdr, bth0, bth2);
        return 1;
 
 bail:
@@ -203,32 +203,39 @@ bail:
 /**
  * ipath_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC)
  * @qp: a pointer to the QP
- * @ohdr: a pointer to the IB header being constructed
- * @pmtu: the path MTU
- * @bth0p: pointer to the BTH opcode word
- * @bth2p: pointer to the BTH PSN word
  *
  * Return 1 if constructed; otherwise, return 0.
- * Note the QP s_lock must be held and interrupts disabled.
  */
-int ipath_make_rc_req(struct ipath_qp *qp,
-                     struct ipath_other_headers *ohdr,
-                     u32 pmtu, u32 *bth0p, u32 *bth2p)
+int ipath_make_rc_req(struct ipath_qp *qp)
 {
        struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+       struct ipath_other_headers *ohdr;
        struct ipath_sge_state *ss;
        struct ipath_swqe *wqe;
        u32 hwords;
        u32 len;
        u32 bth0;
        u32 bth2;
+       u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
        char newreq;
+       unsigned long flags;
+       int ret = 0;
+
+       ohdr = &qp->s_hdr.u.oth;
+       if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+               ohdr = &qp->s_hdr.u.l.oth;
+
+       /*
+        * The lock is needed to synchronize between the sending tasklet,
+        * the receive interrupt handler, and timeout resends.
+        */
+       spin_lock_irqsave(&qp->s_lock, flags);
 
        /* Sending responses has higher priority over sending requests. */
        if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
             (qp->s_flags & IPATH_S_ACK_PENDING) ||
             qp->s_ack_state != OP(ACKNOWLEDGE)) &&
-           ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
+           ipath_make_rc_ack(dev, qp, ohdr, pmtu))
                goto done;
 
        if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
@@ -560,13 +567,12 @@ int ipath_make_rc_req(struct ipath_qp *qp,
        qp->s_hdrwords = hwords;
        qp->s_cur_sge = ss;
        qp->s_cur_size = len;
-       *bth0p = bth0 | (qp->s_state << 24);
-       *bth2p = bth2;
+       ipath_make_ruc_header(dev, qp, ohdr, bth0 | (qp->s_state << 24), bth2);
 done:
-       return 1;
-
+       ret = 1;
 bail:
-       return 0;
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+       return ret;
 }
 
 /**
@@ -581,19 +587,39 @@ bail:
 static void send_rc_ack(struct ipath_qp *qp)
 {
        struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+       struct ipath_devdata *dd;
        u16 lrh0;
        u32 bth0;
        u32 hwords;
+       u32 __iomem *piobuf;
        struct ipath_ib_header hdr;
        struct ipath_other_headers *ohdr;
        unsigned long flags;
 
+       spin_lock_irqsave(&qp->s_lock, flags);
+
        /* Don't send ACK or NAK if a RDMA read or atomic is pending. */
        if (qp->r_head_ack_queue != qp->s_tail_ack_queue ||
            (qp->s_flags & IPATH_S_ACK_PENDING) ||
            qp->s_ack_state != OP(ACKNOWLEDGE))
                goto queue_ack;
 
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+
+       dd = dev->dd;
+       piobuf = ipath_getpiobuf(dd, 0, NULL);
+       if (!piobuf) {
+               /*
+                * We are out of PIO buffers at the moment.
+                * Pass responsibility for sending the ACK to the
+                * send tasklet so that when a PIO buffer becomes
+                * available, the ACK is sent ahead of other outgoing
+                * packets.
+                */
+               spin_lock_irqsave(&qp->s_lock, flags);
+               goto queue_ack;
+       }
+
        /* Construct the header. */
        ohdr = &hdr.u.oth;
        lrh0 = IPATH_LRH_BTH;
@@ -607,7 +633,7 @@ static void send_rc_ack(struct ipath_qp *qp)
                lrh0 = IPATH_LRH_GRH;
        }
        /* read pkey_index w/o lock (its atomic) */
-       bth0 = ipath_get_pkey(dev->dd, qp->s_pkey_index) |
+       bth0 = ipath_get_pkey(dd, qp->s_pkey_index) |
                (OP(ACKNOWLEDGE) << 24) | (1 << 22);
        if (qp->r_nak_state)
                ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
@@ -619,30 +645,30 @@ static void send_rc_ack(struct ipath_qp *qp)
        hdr.lrh[0] = cpu_to_be16(lrh0);
        hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
        hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC);
-       hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
+       hdr.lrh[3] = cpu_to_be16(dd->ipath_lid);
        ohdr->bth[0] = cpu_to_be32(bth0);
        ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
        ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK);
 
-       /*
-        * If we can send the ACK, clear the ACK state.
-        */
-       if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) {
-               dev->n_unicast_xmit++;
-               goto done;
-       }
+       writeq(hwords + 1, piobuf);
 
-       /*
-        * We are out of PIO buffers at the moment.
-        * Pass responsibility for sending the ACK to the
-        * send tasklet so that when a PIO buffer becomes
-        * available, the ACK is sent ahead of other outgoing
-        * packets.
-        */
-       dev->n_rc_qacks++;
+       if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
+               u32 *hdrp = (u32 *) &hdr;
+
+               ipath_flush_wc();
+               __iowrite32_copy(piobuf + 2, hdrp, hwords - 1);
+               ipath_flush_wc();
+               __raw_writel(hdrp[hwords - 1], piobuf + hwords + 1);
+       } else
+               __iowrite32_copy(piobuf + 2, (u32 *) &hdr, hwords);
+
+       ipath_flush_wc();
+
+       dev->n_unicast_xmit++;
+       goto done;
 
 queue_ack:
-       spin_lock_irqsave(&qp->s_lock, flags);
+       dev->n_rc_qacks++;
        qp->s_flags |= IPATH_S_ACK_PENDING;
        qp->s_nak_state = qp->r_nak_state;
        qp->s_ack_psn = qp->r_ack_psn;
@@ -757,7 +783,9 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
                wc->vendor_err = 0;
                wc->byte_len = 0;
                wc->qp = &qp->ibqp;
+               wc->imm_data = 0;
                wc->src_qp = qp->remote_qpn;
+               wc->wc_flags = 0;
                wc->pkey_index = 0;
                wc->slid = qp->remote_ah_attr.dlid;
                wc->sl = qp->remote_ah_attr.sl;
@@ -792,11 +820,13 @@ bail:
 
 static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
 {
-       if (qp->s_wait_credit) {
-               qp->s_wait_credit = 0;
-               tasklet_hi_schedule(&qp->s_task);
+       if (qp->s_last_psn != psn) {
+               qp->s_last_psn = psn;
+               if (qp->s_wait_credit) {
+                       qp->s_wait_credit = 0;
+                       tasklet_hi_schedule(&qp->s_task);
+               }
        }
-       qp->s_last_psn = psn;
 }
 
 /**
@@ -953,8 +983,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
                /* If this is a partial ACK, reset the retransmit timer. */
                if (qp->s_last != qp->s_tail) {
                        spin_lock(&dev->pending_lock);
-                       list_add_tail(&qp->timerwait,
-                                     &dev->pending[dev->pending_index]);
+                       if (list_empty(&qp->timerwait))
+                               list_add_tail(&qp->timerwait,
+                                       &dev->pending[dev->pending_index]);
                        spin_unlock(&dev->pending_lock);
                        /*
                         * If we get a partial ACK for a resent operation,
@@ -1041,7 +1072,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
                        wc.vendor_err = 0;
                        wc.byte_len = 0;
                        wc.qp = &qp->ibqp;
+                       wc.imm_data = 0;
                        wc.src_qp = qp->remote_qpn;
+                       wc.wc_flags = 0;
                        wc.pkey_index = 0;
                        wc.slid = qp->remote_ah_attr.dlid;
                        wc.sl = qp->remote_ah_attr.sl;
@@ -1184,6 +1217,10 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
                        list_move_tail(&qp->timerwait,
                                       &dev->pending[dev->pending_index]);
                spin_unlock(&dev->pending_lock);
+
+               if (opcode == OP(RDMA_READ_RESPONSE_MIDDLE))
+                       qp->s_retry = qp->s_retry_cnt;
+
                /*
                 * Update the RDMA receive state but do the copy w/o
                 * holding the locks and blocking interrupts.
@@ -1453,6 +1490,19 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
                        qp->r_ack_psn = qp->r_psn - 1;
                        goto send_ack;
                }
+               /*
+                * Try to send a simple ACK to work around a Mellanox bug
+                * which doesn't accept a RDMA read response or atomic
+                * response as an ACK for earlier SENDs or RDMA writes.
+                */
+               if (qp->r_head_ack_queue == qp->s_tail_ack_queue &&
+                   !(qp->s_flags & IPATH_S_ACK_PENDING) &&
+                   qp->s_ack_state == OP(ACKNOWLEDGE)) {
+                       spin_unlock_irqrestore(&qp->s_lock, flags);
+                       qp->r_nak_state = 0;
+                       qp->r_ack_psn = qp->s_ack_queue[i].psn - 1;
+                       goto send_ack;
+               }
                /*
                 * Resend the RDMA read or atomic op which
                 * ACKs this duplicate request.
@@ -1476,11 +1526,21 @@ send_ack:
 static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
 {
        unsigned long flags;
+       int lastwqe;
 
        spin_lock_irqsave(&qp->s_lock, flags);
        qp->state = IB_QPS_ERR;
-       ipath_error_qp(qp, err);
+       lastwqe = ipath_error_qp(qp, err);
        spin_unlock_irqrestore(&qp->s_lock, flags);
+
+       if (lastwqe) {
+               struct ib_event ev;
+
+               ev.device = qp->ibqp.device;
+               ev.element.qp = &qp->ibqp;
+               ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+               qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+       }
 }
 
 static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n)
@@ -1621,13 +1681,6 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
        case OP(SEND_FIRST):
                if (!ipath_get_rwqe(qp, 0)) {
                rnr_nak:
-                       /*
-                        * A RNR NAK will ACK earlier sends and RDMA writes.
-                        * Don't queue the NAK if a RDMA read or atomic
-                        * is pending though.
-                        */
-                       if (qp->r_nak_state)
-                               goto done;
                        qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
                        qp->r_ack_psn = qp->r_psn;
                        goto send_ack;