Merge branch 'e1000-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[pandora-kernel.git] / drivers / infiniband / hw / ipath / ipath_rc.c
index 5ff20cb..b4b88d0 100644 (file)
 /* cut down ridiculously long IB macro names */
 #define OP(x) IB_OPCODE_RC_##x
 
+static u32 restart_sge(struct ipath_sge_state *ss, struct ipath_swqe *wqe,
+                      u32 psn, u32 pmtu)
+{
+       u32 len;
+
+       len = ((psn - wqe->psn) & IPATH_PSN_MASK) * pmtu;
+       ss->sge = wqe->sg_list[0];
+       ss->sg_list = wqe->sg_list + 1;
+       ss->num_sge = wqe->wr.num_sge;
+       ipath_skip_sge(ss, len);
+       return wqe->length - len;
+}
+
 /**
  * ipath_init_restart- initialize the qp->s_sge after a restart
  * @qp: the QP who's SGE we're restarting
 static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
 {
        struct ipath_ibdev *dev;
-       u32 len;
 
-       len = ((qp->s_psn - wqe->psn) & IPATH_PSN_MASK) *
-               ib_mtu_enum_to_int(qp->path_mtu);
-       qp->s_sge.sge = wqe->sg_list[0];
-       qp->s_sge.sg_list = wqe->sg_list + 1;
-       qp->s_sge.num_sge = wqe->wr.num_sge;
-       ipath_skip_sge(&qp->s_sge, len);
-       qp->s_len = wqe->length - len;
+       qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn,
+                               ib_mtu_enum_to_int(qp->path_mtu));
        dev = to_idev(qp->ibqp.device);
        spin_lock(&dev->pending_lock);
        if (list_empty(&qp->timerwait))
@@ -70,107 +77,123 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
  * @ohdr: a pointer to the IB header being constructed
  * @pmtu: the path MTU
  *
- * Return bth0 if constructed; otherwise, return 0.
+ * Return 1 if constructed; otherwise, return 0.
+ * Note that we are in the responder's side of the QP context.
  * Note the QP s_lock must be held.
  */
-u32 ipath_make_rc_ack(struct ipath_qp *qp,
-                     struct ipath_other_headers *ohdr,
-                     u32 pmtu)
+static int ipath_make_rc_ack(struct ipath_qp *qp,
+                            struct ipath_other_headers *ohdr,
+                            u32 pmtu, u32 *bth0p, u32 *bth2p)
 {
+       struct ipath_ack_entry *e;
        u32 hwords;
        u32 len;
        u32 bth0;
+       u32 bth2;
 
        /* header size in 32-bit words LRH+BTH = (8+12)/4. */
        hwords = 5;
 
-       /*
-        * Send a response.  Note that we are in the responder's
-        * side of the QP context.
-        */
        switch (qp->s_ack_state) {
-       case OP(RDMA_READ_REQUEST):
-               qp->s_cur_sge = &qp->s_rdma_sge;
-               len = qp->s_rdma_len;
-               if (len > pmtu) {
-                       len = pmtu;
-                       qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
-               } else
-                       qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
-               qp->s_rdma_len -= len;
+       case OP(RDMA_READ_RESPONSE_LAST):
+       case OP(RDMA_READ_RESPONSE_ONLY):
+       case OP(ATOMIC_ACKNOWLEDGE):
+               qp->s_ack_state = OP(ACKNOWLEDGE);
+               /* FALLTHROUGH */
+       case OP(ACKNOWLEDGE):
+               /* Check for no next entry in the queue. */
+               if (qp->r_head_ack_queue == qp->s_tail_ack_queue) {
+                       if (qp->s_flags & IPATH_S_ACK_PENDING)
+                               goto normal;
+                       goto bail;
+               }
+
+               e = &qp->s_ack_queue[qp->s_tail_ack_queue];
+               if (e->opcode == OP(RDMA_READ_REQUEST)) {
+                       /* Copy SGE state in case we need to resend */
+                       qp->s_ack_rdma_sge = e->rdma_sge;
+                       qp->s_cur_sge = &qp->s_ack_rdma_sge;
+                       len = e->rdma_sge.sge.sge_length;
+                       if (len > pmtu) {
+                               len = pmtu;
+                               qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
+                       } else {
+                               qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
+                               if (++qp->s_tail_ack_queue >
+                                   IPATH_MAX_RDMA_ATOMIC)
+                                       qp->s_tail_ack_queue = 0;
+                       }
+                       ohdr->u.aeth = ipath_compute_aeth(qp);
+                       hwords++;
+                       qp->s_ack_rdma_psn = e->psn;
+                       bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
+               } else {
+                       /* COMPARE_SWAP or FETCH_ADD */
+                       qp->s_cur_sge = NULL;
+                       len = 0;
+                       qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE);
+                       ohdr->u.at.aeth = ipath_compute_aeth(qp);
+                       ohdr->u.at.atomic_ack_eth[0] =
+                               cpu_to_be32(e->atomic_data >> 32);
+                       ohdr->u.at.atomic_ack_eth[1] =
+                               cpu_to_be32(e->atomic_data);
+                       hwords += sizeof(ohdr->u.at) / sizeof(u32);
+                       bth2 = e->psn;
+                       if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC)
+                               qp->s_tail_ack_queue = 0;
+               }
                bth0 = qp->s_ack_state << 24;
-               ohdr->u.aeth = ipath_compute_aeth(qp);
-               hwords++;
                break;
 
        case OP(RDMA_READ_RESPONSE_FIRST):
                qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE);
                /* FALLTHROUGH */
        case OP(RDMA_READ_RESPONSE_MIDDLE):
-               qp->s_cur_sge = &qp->s_rdma_sge;
-               len = qp->s_rdma_len;
+               len = qp->s_ack_rdma_sge.sge.sge_length;
                if (len > pmtu)
                        len = pmtu;
                else {
                        ohdr->u.aeth = ipath_compute_aeth(qp);
                        hwords++;
                        qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
+                       if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC)
+                               qp->s_tail_ack_queue = 0;
                }
-               qp->s_rdma_len -= len;
                bth0 = qp->s_ack_state << 24;
-               break;
-
-       case OP(RDMA_READ_RESPONSE_LAST):
-       case OP(RDMA_READ_RESPONSE_ONLY):
-               /*
-                * We have to prevent new requests from changing
-                * the r_sge state while a ipath_verbs_send()
-                * is in progress.
-                */
-               qp->s_ack_state = OP(ACKNOWLEDGE);
-               bth0 = 0;
-               goto bail;
-
-       case OP(COMPARE_SWAP):
-       case OP(FETCH_ADD):
-               qp->s_cur_sge = NULL;
-               len = 0;
-               /*
-                * Set the s_ack_state so the receive interrupt handler
-                * won't try to send an ACK (out of order) until this one
-                * is actually sent.
-                */
-               qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
-               bth0 = OP(ATOMIC_ACKNOWLEDGE) << 24;
-               ohdr->u.at.aeth = ipath_compute_aeth(qp);
-               ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->r_atomic_data);
-               hwords += sizeof(ohdr->u.at) / 4;
+               bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
                break;
 
        default:
-               /* Send a regular ACK. */
-               qp->s_cur_sge = NULL;
-               len = 0;
+       normal:
                /*
-                * Set the s_ack_state so the receive interrupt handler
-                * won't try to send an ACK (out of order) until this one
-                * is actually sent.
+                * Send a regular ACK.
+                * Set the s_ack_state so we wait until after sending
+                * the ACK before setting s_ack_state to ACKNOWLEDGE
+                * (see above).
                 */
-               qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
-               bth0 = OP(ACKNOWLEDGE) << 24;
+               qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE);
+               qp->s_flags &= ~IPATH_S_ACK_PENDING;
+               qp->s_cur_sge = NULL;
                if (qp->s_nak_state)
-                       ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
-                                                   (qp->s_nak_state <<
-                                                    IPATH_AETH_CREDIT_SHIFT));
+                       ohdr->u.aeth =
+                               cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
+                                           (qp->s_nak_state <<
+                                            IPATH_AETH_CREDIT_SHIFT));
                else
                        ohdr->u.aeth = ipath_compute_aeth(qp);
                hwords++;
+               len = 0;
+               bth0 = OP(ACKNOWLEDGE) << 24;
+               bth2 = qp->s_ack_psn & IPATH_PSN_MASK;
        }
        qp->s_hdrwords = hwords;
        qp->s_cur_size = len;
+       *bth0p = bth0;
+       *bth2p = bth2;
+       return 1;
 
 bail:
-       return bth0;
+       return 0;
 }
 
 /**
@@ -197,9 +220,16 @@ int ipath_make_rc_req(struct ipath_qp *qp,
        u32 bth2;
        char newreq;
 
+       /* 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 != IB_OPCODE_RC_ACKNOWLEDGE) &&
+           ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
+               goto done;
+
        if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
            qp->s_rnr_timeout)
-               goto done;
+               goto bail;
 
        /* Limit the number of packets sent without an ACK. */
        if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) {
@@ -210,7 +240,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                        list_add_tail(&qp->timerwait,
                                      &dev->pending[dev->pending_index]);
                spin_unlock(&dev->pending_lock);
-               goto done;
+               goto bail;
        }
 
        /* header size in 32-bit words LRH+BTH = (8+12)/4. */
@@ -232,7 +262,16 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                if (qp->s_cur == qp->s_tail) {
                        /* Check if send work queue is empty. */
                        if (qp->s_tail == qp->s_head)
-                               goto done;
+                               goto bail;
+                       /*
+                        * If a fence is requested, wait for previous
+                        * RDMA read and atomic operations to finish.
+                        */
+                       if ((wqe->wr.send_flags & IB_SEND_FENCE) &&
+                           qp->s_num_rd_atomic) {
+                               qp->s_flags |= IPATH_S_FENCE_PENDING;
+                               goto bail;
+                       }
                        wqe->psn = qp->s_next_psn;
                        newreq = 1;
                }
@@ -250,7 +289,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                        /* If no credit, return. */
                        if (qp->s_lsn != (u32) -1 &&
                            ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0)
-                               goto done;
+                               goto bail;
                        wqe->lpsn = wqe->psn;
                        if (len > pmtu) {
                                wqe->lpsn += (len - 1) / pmtu;
@@ -281,13 +320,13 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                        /* If no credit, return. */
                        if (qp->s_lsn != (u32) -1 &&
                            ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0)
-                               goto done;
+                               goto bail;
                        ohdr->u.rc.reth.vaddr =
                                cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
                        ohdr->u.rc.reth.rkey =
                                cpu_to_be32(wqe->wr.wr.rdma.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
-                       hwords += sizeof(struct ib_reth) / 4;
+                       hwords += sizeof(struct ib_reth) / sizeof(u32);
                        wqe->lpsn = wqe->psn;
                        if (len > pmtu) {
                                wqe->lpsn += (len - 1) / pmtu;
@@ -312,14 +351,17 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                        break;
 
                case IB_WR_RDMA_READ:
-                       ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
-                       ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
-                       ohdr->u.rc.reth.length = cpu_to_be32(len);
-                       qp->s_state = OP(RDMA_READ_REQUEST);
-                       hwords += sizeof(ohdr->u.rc.reth) / 4;
+                       /*
+                        * Don't allow more operations to be started
+                        * than the QP limits allow.
+                        */
                        if (newreq) {
+                               if (qp->s_num_rd_atomic >=
+                                   qp->s_max_rd_atomic) {
+                                       qp->s_flags |= IPATH_S_RDMAR_PENDING;
+                                       goto bail;
+                               }
+                               qp->s_num_rd_atomic++;
                                if (qp->s_lsn != (u32) -1)
                                        qp->s_lsn++;
                                /*
@@ -330,6 +372,13 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                                        qp->s_next_psn += (len - 1) / pmtu;
                                wqe->lpsn = qp->s_next_psn++;
                        }
+                       ohdr->u.rc.reth.vaddr =
+                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                       ohdr->u.rc.reth.rkey =
+                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                       ohdr->u.rc.reth.length = cpu_to_be32(len);
+                       qp->s_state = OP(RDMA_READ_REQUEST);
+                       hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
                        ss = NULL;
                        len = 0;
                        if (++qp->s_cur == qp->s_size)
@@ -338,32 +387,48 @@ int ipath_make_rc_req(struct ipath_qp *qp,
 
                case IB_WR_ATOMIC_CMP_AND_SWP:
                case IB_WR_ATOMIC_FETCH_AND_ADD:
-                       if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP)
-                               qp->s_state = OP(COMPARE_SWAP);
-                       else
-                               qp->s_state = OP(FETCH_ADD);
-                       ohdr->u.atomic_eth.vaddr = cpu_to_be64(
-                               wqe->wr.wr.atomic.remote_addr);
-                       ohdr->u.atomic_eth.rkey = cpu_to_be32(
-                               wqe->wr.wr.atomic.rkey);
-                       ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-                               wqe->wr.wr.atomic.swap);
-                       ohdr->u.atomic_eth.compare_data = cpu_to_be64(
-                               wqe->wr.wr.atomic.compare_add);
-                       hwords += sizeof(struct ib_atomic_eth) / 4;
+                       /*
+                        * Don't allow more operations to be started
+                        * than the QP limits allow.
+                        */
                        if (newreq) {
+                               if (qp->s_num_rd_atomic >=
+                                   qp->s_max_rd_atomic) {
+                                       qp->s_flags |= IPATH_S_RDMAR_PENDING;
+                                       goto bail;
+                               }
+                               qp->s_num_rd_atomic++;
                                if (qp->s_lsn != (u32) -1)
                                        qp->s_lsn++;
                                wqe->lpsn = wqe->psn;
                        }
-                       if (++qp->s_cur == qp->s_size)
-                               qp->s_cur = 0;
+                       if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+                               qp->s_state = OP(COMPARE_SWAP);
+                               ohdr->u.atomic_eth.swap_data = cpu_to_be64(
+                                       wqe->wr.wr.atomic.swap);
+                               ohdr->u.atomic_eth.compare_data = cpu_to_be64(
+                                       wqe->wr.wr.atomic.compare_add);
+                       } else {
+                               qp->s_state = OP(FETCH_ADD);
+                               ohdr->u.atomic_eth.swap_data = cpu_to_be64(
+                                       wqe->wr.wr.atomic.compare_add);
+                               ohdr->u.atomic_eth.compare_data = 0;
+                       }
+                       ohdr->u.atomic_eth.vaddr[0] = cpu_to_be32(
+                               wqe->wr.wr.atomic.remote_addr >> 32);
+                       ohdr->u.atomic_eth.vaddr[1] = cpu_to_be32(
+                               wqe->wr.wr.atomic.remote_addr);
+                       ohdr->u.atomic_eth.rkey = cpu_to_be32(
+                               wqe->wr.wr.atomic.rkey);
+                       hwords += sizeof(struct ib_atomic_eth) / sizeof(u32);
                        ss = NULL;
                        len = 0;
+                       if (++qp->s_cur == qp->s_size)
+                               qp->s_cur = 0;
                        break;
 
                default:
-                       goto done;
+                       goto bail;
                }
                qp->s_sge.sge = wqe->sg_list[0];
                qp->s_sge.sg_list = wqe->sg_list + 1;
@@ -379,7 +444,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                        qp->s_psn = wqe->lpsn + 1;
                else {
                        qp->s_psn++;
-                       if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+                       if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
                                qp->s_next_psn = qp->s_psn;
                }
                /*
@@ -406,7 +471,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                /* FALLTHROUGH */
        case OP(SEND_MIDDLE):
                bth2 = qp->s_psn++ & IPATH_PSN_MASK;
-               if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+               if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
                        qp->s_next_psn = qp->s_psn;
                ss = &qp->s_sge;
                len = qp->s_len;
@@ -442,7 +507,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                /* FALLTHROUGH */
        case OP(RDMA_WRITE_MIDDLE):
                bth2 = qp->s_psn++ & IPATH_PSN_MASK;
-               if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+               if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
                        qp->s_next_psn = qp->s_psn;
                ss = &qp->s_sge;
                len = qp->s_len;
@@ -479,9 +544,9 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                        cpu_to_be32(wqe->wr.wr.rdma.rkey);
                ohdr->u.rc.reth.length = cpu_to_be32(qp->s_len);
                qp->s_state = OP(RDMA_READ_REQUEST);
-               hwords += sizeof(ohdr->u.rc.reth) / 4;
+               hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
                bth2 = qp->s_psn++ & IPATH_PSN_MASK;
-               if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+               if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
                        qp->s_next_psn = qp->s_psn;
                ss = NULL;
                len = 0;
@@ -489,20 +554,6 @@ int ipath_make_rc_req(struct ipath_qp *qp,
                if (qp->s_cur == qp->s_size)
                        qp->s_cur = 0;
                break;
-
-       case OP(RDMA_READ_REQUEST):
-       case OP(COMPARE_SWAP):
-       case OP(FETCH_ADD):
-               /*
-                * We shouldn't start anything new until this request is
-                * finished.  The ACK will handle rescheduling us.  XXX The
-                * number of outstanding ones is negotiated at connection
-                * setup time (see pg. 258,289)?  XXX Also, if we support
-                * multiple outstanding requests, we need to check the WQE
-                * IB_SEND_FENCE flag and not send a new request if a RDMA
-                * read or atomic is pending.
-                */
-               goto done;
        }
        if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT - 1) >= 0)
                bth2 |= 1 << 31;        /* Request ACK. */
@@ -512,9 +563,10 @@ int ipath_make_rc_req(struct ipath_qp *qp,
        qp->s_cur_size = len;
        *bth0p = bth0 | (qp->s_state << 24);
        *bth2p = bth2;
+done:
        return 1;
 
-done:
+bail:
        return 0;
 }
 
@@ -524,7 +576,8 @@ done:
  *
  * This is called from ipath_rc_rcv() and only uses the receive
  * side QP state.
- * Note that RDMA reads are handled in the send side QP state and tasklet.
+ * Note that RDMA reads and atomics are handled in the
+ * send side QP state and tasklet.
  */
 static void send_rc_ack(struct ipath_qp *qp)
 {
@@ -535,6 +588,10 @@ static void send_rc_ack(struct ipath_qp *qp)
        struct ipath_ib_header hdr;
        struct ipath_other_headers *ohdr;
 
+       /* 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)
+               goto queue_ack;
+
        /* Construct the header. */
        ohdr = &hdr.u.oth;
        lrh0 = IPATH_LRH_BTH;
@@ -548,19 +605,14 @@ 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(dev->dd, qp->s_pkey_index) |
+               OP(ACKNOWLEDGE) << 24;
        if (qp->r_nak_state)
                ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
                                            (qp->r_nak_state <<
                                             IPATH_AETH_CREDIT_SHIFT));
        else
                ohdr->u.aeth = ipath_compute_aeth(qp);
-       if (qp->r_ack_state >= OP(COMPARE_SWAP)) {
-               bth0 |= OP(ATOMIC_ACKNOWLEDGE) << 24;
-               ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->r_atomic_data);
-               hwords += sizeof(ohdr->u.at.atomic_ack_eth) / 4;
-       } else
-               bth0 |= OP(ACKNOWLEDGE) << 24;
        lrh0 |= qp->remote_ah_attr.sl << 4;
        hdr.lrh[0] = cpu_to_be16(lrh0);
        hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
@@ -574,31 +626,31 @@ static void send_rc_ack(struct ipath_qp *qp)
         * If we can send the ACK, clear the ACK state.
         */
        if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) {
-               qp->r_ack_state = OP(ACKNOWLEDGE);
                dev->n_unicast_xmit++;
-       } else {
-               /*
-                * 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++;
-               spin_lock_irq(&qp->s_lock);
-               /* Don't coalesce if a RDMA read or atomic is pending. */
-               if (qp->s_ack_state == OP(ACKNOWLEDGE) ||
-                   qp->s_ack_state < OP(RDMA_READ_REQUEST)) {
-                       qp->s_ack_state = qp->r_ack_state;
-                       qp->s_nak_state = qp->r_nak_state;
-                       qp->s_ack_psn = qp->r_ack_psn;
-                       qp->r_ack_state = OP(ACKNOWLEDGE);
-               }
-               spin_unlock_irq(&qp->s_lock);
-
-               /* Call ipath_do_rc_send() in another thread. */
-               tasklet_hi_schedule(&qp->s_task);
+               goto done;
        }
+
+       /*
+        * 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++;
+
+queue_ack:
+       spin_lock_irq(&qp->s_lock);
+       qp->s_flags |= IPATH_S_ACK_PENDING;
+       qp->s_nak_state = qp->r_nak_state;
+       qp->s_ack_psn = qp->r_ack_psn;
+       spin_unlock_irq(&qp->s_lock);
+
+       /* Call ipath_do_rc_send() in another thread. */
+       tasklet_hi_schedule(&qp->s_task);
+
+done:
+       return;
 }
 
 /**
@@ -727,7 +779,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
        if (wqe->wr.opcode == IB_WR_RDMA_READ)
                dev->n_rc_resends++;
        else
-               dev->n_rc_resends += (int)qp->s_psn - (int)psn;
+               dev->n_rc_resends += (qp->s_psn - psn) & IPATH_PSN_MASK;
 
        reset_psn(qp, psn);
        tasklet_hi_schedule(&qp->s_task);
@@ -775,10 +827,6 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
                list_del_init(&qp->timerwait);
        spin_unlock(&dev->pending_lock);
 
-       /* Nothing is pending to ACK/NAK. */
-       if (unlikely(qp->s_last == qp->s_tail))
-               goto bail;
-
        /*
         * Note that NAKs implicitly ACK outstanding SEND and RDMA write
         * requests and implicitly NAK RDMA read and atomic requests issued
@@ -806,7 +854,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
                 */
                if ((wqe->wr.opcode == IB_WR_RDMA_READ &&
                     (opcode != OP(RDMA_READ_RESPONSE_LAST) ||
-                      ipath_cmp24(ack_psn, wqe->lpsn) != 0)) ||
+                     ipath_cmp24(ack_psn, wqe->lpsn) != 0)) ||
                    ((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
                      wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) &&
                     (opcode != OP(ATOMIC_ACKNOWLEDGE) ||
@@ -824,20 +872,33 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
                         */
                        goto bail;
                }
-               if (wqe->wr.opcode == IB_WR_RDMA_READ ||
-                   wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
-                   wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
-                       tasklet_hi_schedule(&qp->s_task);
+               if (qp->s_num_rd_atomic &&
+                   (wqe->wr.opcode == IB_WR_RDMA_READ ||
+                    wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+                    wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)) {
+                       qp->s_num_rd_atomic--;
+                       /* Restart sending task if fence is complete */
+                       if ((qp->s_flags & IPATH_S_FENCE_PENDING) &&
+                           !qp->s_num_rd_atomic) {
+                               qp->s_flags &= ~IPATH_S_FENCE_PENDING;
+                               tasklet_hi_schedule(&qp->s_task);
+                       } else if (qp->s_flags & IPATH_S_RDMAR_PENDING) {
+                               qp->s_flags &= ~IPATH_S_RDMAR_PENDING;
+                               tasklet_hi_schedule(&qp->s_task);
+                       }
+               }
                /* Post a send completion queue entry if requested. */
-               if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) ||
+               if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
                    (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
                        wc.wr_id = wqe->wr.wr_id;
                        wc.status = IB_WC_SUCCESS;
                        wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
                        wc.vendor_err = 0;
                        wc.byte_len = wqe->length;
+                       wc.imm_data = 0;
                        wc.qp = &qp->ibqp;
                        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;
@@ -854,15 +915,19 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
                if (qp->s_last == qp->s_cur) {
                        if (++qp->s_cur >= qp->s_size)
                                qp->s_cur = 0;
+                       qp->s_last = qp->s_cur;
+                       if (qp->s_last == qp->s_tail)
+                               break;
                        wqe = get_swqe_ptr(qp, qp->s_cur);
                        qp->s_state = OP(SEND_LAST);
                        qp->s_psn = wqe->psn;
+               } else {
+                       if (++qp->s_last >= qp->s_size)
+                               qp->s_last = 0;
+                       if (qp->s_last == qp->s_tail)
+                               break;
+                       wqe = get_swqe_ptr(qp, qp->s_last);
                }
-               if (++qp->s_last >= qp->s_size)
-                       qp->s_last = 0;
-               wqe = get_swqe_ptr(qp, qp->s_last);
-               if (qp->s_last == qp->s_tail)
-                       break;
        }
 
        switch (aeth >> 29) {
@@ -874,6 +939,18 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
                        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,
+                        * we can stop resending the earlier packets and
+                        * continue with the next packet the receiver wants.
+                        */
+                       if (ipath_cmp24(qp->s_psn, psn) <= 0) {
+                               reset_psn(qp, psn + 1);
+                               tasklet_hi_schedule(&qp->s_task);
+                       }
+               } else if (ipath_cmp24(qp->s_psn, psn) <= 0) {
+                       qp->s_state = OP(SEND_LAST);
+                       qp->s_psn = psn + 1;
                }
                ipath_get_credit(qp, aeth);
                qp->s_rnr_retry = qp->s_rnr_retry_cnt;
@@ -884,22 +961,23 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
 
        case 1:         /* RNR NAK */
                dev->n_rnr_naks++;
+               if (qp->s_last == qp->s_tail)
+                       goto bail;
                if (qp->s_rnr_retry == 0) {
-                       if (qp->s_last == qp->s_tail)
-                               goto bail;
-
                        wc.status = IB_WC_RNR_RETRY_EXC_ERR;
                        goto class_b;
                }
                if (qp->s_rnr_retry_cnt < 7)
                        qp->s_rnr_retry--;
-               if (qp->s_last == qp->s_tail)
-                       goto bail;
 
                /* The last valid PSN is the previous PSN. */
                update_last_psn(qp, psn - 1);
 
-               dev->n_rc_resends += (int)qp->s_psn - (int)psn;
+               if (wqe->wr.opcode == IB_WR_RDMA_READ)
+                       dev->n_rc_resends++;
+               else
+                       dev->n_rc_resends +=
+                               (qp->s_psn - psn) & IPATH_PSN_MASK;
 
                reset_psn(qp, psn);
 
@@ -910,26 +988,20 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
                goto bail;
 
        case 3:         /* NAK */
-               /* The last valid PSN seen is the previous request's. */
-               if (qp->s_last != qp->s_tail)
-                       update_last_psn(qp, wqe->psn - 1);
+               if (qp->s_last == qp->s_tail)
+                       goto bail;
+               /* The last valid PSN is the previous PSN. */
+               update_last_psn(qp, psn - 1);
                switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) &
                        IPATH_AETH_CREDIT_MASK) {
                case 0: /* PSN sequence error */
                        dev->n_seq_naks++;
                        /*
-                        * Back up to the responder's expected PSN.  XXX
+                        * Back up to the responder's expected PSN.
                         * Note that we might get a NAK in the middle of an
                         * RDMA READ response which terminates the RDMA
                         * READ.
                         */
-                       if (qp->s_last == qp->s_tail)
-                               break;
-
-                       if (ipath_cmp24(psn, wqe->psn) < 0)
-                               break;
-
-                       /* Retry the request. */
                        ipath_restart_rc(qp, psn, &wc);
                        break;
 
@@ -1003,6 +1075,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
                                     u32 psn, u32 hdrsize, u32 pmtu,
                                     int header_in_data)
 {
+       struct ipath_swqe *wqe;
        unsigned long flags;
        struct ib_wc wc;
        int diff;
@@ -1032,6 +1105,10 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
                goto ack_done;
        }
 
+       if (unlikely(qp->s_last == qp->s_tail))
+               goto ack_done;
+       wqe = get_swqe_ptr(qp, qp->s_last);
+
        switch (opcode) {
        case OP(ACKNOWLEDGE):
        case OP(ATOMIC_ACKNOWLEDGE):
@@ -1042,38 +1119,49 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
                        aeth = be32_to_cpu(((__be32 *) data)[0]);
                        data += sizeof(__be32);
                }
-               if (opcode == OP(ATOMIC_ACKNOWLEDGE))
-                       *(u64 *) qp->s_sge.sge.vaddr = *(u64 *) data;
+               if (opcode == OP(ATOMIC_ACKNOWLEDGE)) {
+                       u64 val;
+
+                       if (!header_in_data) {
+                               __be32 *p = ohdr->u.at.atomic_ack_eth;
+
+                               val = ((u64) be32_to_cpu(p[0]) << 32) |
+                                       be32_to_cpu(p[1]);
+                       } else
+                               val = be64_to_cpu(((__be64 *) data)[0]);
+                       *(u64 *) wqe->sg_list[0].vaddr = val;
+               }
                if (!do_rc_ack(qp, aeth, psn, opcode) ||
                    opcode != OP(RDMA_READ_RESPONSE_FIRST))
                        goto ack_done;
                hdrsize += 4;
+               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+                       goto ack_op_err;
                /*
-                * do_rc_ack() has already checked the PSN so skip
-                * the sequence check.
+                * If this is a response to a resent RDMA read, we
+                * have to be careful to copy the data to the right
+                * location.
                 */
-               goto rdma_read;
+               qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
+                                                 wqe, psn, pmtu);
+               goto read_middle;
 
        case OP(RDMA_READ_RESPONSE_MIDDLE):
                /* no AETH, no ACK */
                if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
                        dev->n_rdma_seq++;
-                       if (qp->s_last != qp->s_tail)
-                               ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+                       ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
                        goto ack_done;
                }
-       rdma_read:
-               if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST)))
-                       goto ack_done;
+               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+                       goto ack_op_err;
+       read_middle:
                if (unlikely(tlen != (hdrsize + pmtu + 4)))
-                       goto ack_done;
-               if (unlikely(pmtu >= qp->s_len))
-                       goto ack_done;
+                       goto ack_len_err;
+               if (unlikely(pmtu >= qp->s_rdma_read_len))
+                       goto ack_len_err;
+
                /* We got a response so update the timeout. */
-               if (unlikely(qp->s_last == qp->s_tail ||
-                            get_swqe_ptr(qp, qp->s_last)->wr.opcode !=
-                            IB_WR_RDMA_READ))
-                       goto ack_done;
                spin_lock(&dev->pending_lock);
                if (qp->s_rnr_timeout == 0 && !list_empty(&qp->timerwait))
                        list_move_tail(&qp->timerwait,
@@ -1082,67 +1170,97 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
                /*
                 * Update the RDMA receive state but do the copy w/o
                 * holding the locks and blocking interrupts.
-                * XXX Yet another place that affects relaxed RDMA order
-                * since we don't want s_sge modified.
                 */
-               qp->s_len -= pmtu;
+               qp->s_rdma_read_len -= pmtu;
                update_last_psn(qp, psn);
                spin_unlock_irqrestore(&qp->s_lock, flags);
-               ipath_copy_sge(&qp->s_sge, data, pmtu);
+               ipath_copy_sge(&qp->s_rdma_read_sge, data, pmtu);
                goto bail;
 
-       case OP(RDMA_READ_RESPONSE_LAST):
-               /* ACKs READ req. */
+       case OP(RDMA_READ_RESPONSE_ONLY):
                if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
                        dev->n_rdma_seq++;
-                       if (qp->s_last != qp->s_tail)
-                               ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+                       ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
                        goto ack_done;
                }
-               /* FALLTHROUGH */
-       case OP(RDMA_READ_RESPONSE_ONLY):
-               if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST)))
-                       goto ack_done;
+               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+                       goto ack_op_err;
+               /* Get the number of bytes the message was padded by. */
+               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+               /*
+                * Check that the data size is >= 0 && <= pmtu.
+                * Remember to account for the AETH header (4) and
+                * ICRC (4).
+                */
+               if (unlikely(tlen < (hdrsize + pad + 8)))
+                       goto ack_len_err;
                /*
-                * Get the number of bytes the message was padded by.
+                * If this is a response to a resent RDMA read, we
+                * have to be careful to copy the data to the right
+                * location.
                 */
+               qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
+                                                 wqe, psn, pmtu);
+               goto read_last;
+
+       case OP(RDMA_READ_RESPONSE_LAST):
+               /* ACKs READ req. */
+               if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
+                       dev->n_rdma_seq++;
+                       ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+                       goto ack_done;
+               }
+               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+                       goto ack_op_err;
+               /* Get the number of bytes the message was padded by. */
                pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
                /*
                 * Check that the data size is >= 1 && <= pmtu.
                 * Remember to account for the AETH header (4) and
                 * ICRC (4).
                 */
-               if (unlikely(tlen <= (hdrsize + pad + 8))) {
-                       /* XXX Need to generate an error CQ entry. */
-                       goto ack_done;
-               }
+               if (unlikely(tlen <= (hdrsize + pad + 8)))
+                       goto ack_len_err;
+       read_last:
                tlen -= hdrsize + pad + 8;
-               if (unlikely(tlen != qp->s_len)) {
-                       /* XXX Need to generate an error CQ entry. */
-                       goto ack_done;
-               }
+               if (unlikely(tlen != qp->s_rdma_read_len))
+                       goto ack_len_err;
                if (!header_in_data)
                        aeth = be32_to_cpu(ohdr->u.aeth);
                else {
                        aeth = be32_to_cpu(((__be32 *) data)[0]);
                        data += sizeof(__be32);
                }
-               ipath_copy_sge(&qp->s_sge, data, tlen);
-               if (do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST))) {
-                       /*
-                        * Change the state so we contimue
-                        * processing new requests and wake up the
-                        * tasklet if there are posted sends.
-                        */
-                       qp->s_state = OP(SEND_LAST);
-                       if (qp->s_tail != qp->s_head)
-                               tasklet_hi_schedule(&qp->s_task);
-               }
+               ipath_copy_sge(&qp->s_rdma_read_sge, data, tlen);
+               (void) do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST));
                goto ack_done;
        }
 
 ack_done:
        spin_unlock_irqrestore(&qp->s_lock, flags);
+       goto bail;
+
+ack_op_err:
+       wc.status = IB_WC_LOC_QP_OP_ERR;
+       goto ack_err;
+
+ack_len_err:
+       wc.status = IB_WC_LOC_LEN_ERR;
+ack_err:
+       wc.wr_id = wqe->wr.wr_id;
+       wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
+       wc.vendor_err = 0;
+       wc.byte_len = 0;
+       wc.imm_data = 0;
+       wc.qp = &qp->ibqp;
+       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;
+       wc.dlid_path_bits = 0;
+       wc.port_num = 0;
+       ipath_sqerror_qp(qp, &wc);
 bail:
        return;
 }
@@ -1162,7 +1280,7 @@ bail:
  * incoming RC packet for the given QP.
  * Called at interrupt level.
  * Return 1 if no more processing is needed; otherwise return 0 to
- * schedule a response to be sent and the s_lock unlocked.
+ * schedule a response to be sent.
  */
 static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
                                     struct ipath_other_headers *ohdr,
@@ -1173,25 +1291,23 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
                                     int diff,
                                     int header_in_data)
 {
-       struct ib_reth *reth;
+       struct ipath_ack_entry *e;
+       u8 i, prev;
+       int old_req;
 
        if (diff > 0) {
                /*
                 * Packet sequence error.
                 * A NAK will ACK earlier sends and RDMA writes.
-                * Don't queue the NAK if a RDMA read, atomic, or
-                * NAK is pending though.
+                * Don't queue the NAK if we already sent one.
                 */
-               if (qp->s_ack_state != OP(ACKNOWLEDGE) ||
-                   qp->r_nak_state != 0)
-                       goto done;
-               if (qp->r_ack_state < OP(COMPARE_SWAP)) {
-                       qp->r_ack_state = OP(SEND_ONLY);
+               if (!qp->r_nak_state) {
                        qp->r_nak_state = IB_NAK_PSN_ERROR;
                        /* Use the expected PSN. */
                        qp->r_ack_psn = qp->r_psn;
+                       goto send_ack;
                }
-               goto send_ack;
+               goto done;
        }
 
        /*
@@ -1204,8 +1320,46 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
         * can coalesce an outstanding duplicate ACK.  We have to
         * send the earliest so that RDMA reads can be restarted at
         * the requester's expected PSN.
+        *
+        * First, find where this duplicate PSN falls within the
+        * ACKs previously sent.
         */
-       if (opcode == OP(RDMA_READ_REQUEST)) {
+       psn &= IPATH_PSN_MASK;
+       e = NULL;
+       old_req = 1;
+       spin_lock_irq(&qp->s_lock);
+       for (i = qp->r_head_ack_queue; ; i = prev) {
+               if (i == qp->s_tail_ack_queue)
+                       old_req = 0;
+               if (i)
+                       prev = i - 1;
+               else
+                       prev = IPATH_MAX_RDMA_ATOMIC;
+               if (prev == qp->r_head_ack_queue) {
+                       e = NULL;
+                       break;
+               }
+               e = &qp->s_ack_queue[prev];
+               if (!e->opcode) {
+                       e = NULL;
+                       break;
+               }
+               if (ipath_cmp24(psn, e->psn) >= 0)
+                       break;
+       }
+       switch (opcode) {
+       case OP(RDMA_READ_REQUEST): {
+               struct ib_reth *reth;
+               u32 offset;
+               u32 len;
+
+               /*
+                * If we didn't find the RDMA read request in the ack queue,
+                * or the send tasklet is already backed up to send an
+                * earlier entry, we can ignore this request.
+                */
+               if (!e || e->opcode != OP(RDMA_READ_REQUEST) || old_req)
+                       goto unlock_done;
                /* RETH comes after BTH */
                if (!header_in_data)
                        reth = &ohdr->u.rc.reth;
@@ -1214,88 +1368,87 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
                        data += sizeof(*reth);
                }
                /*
-                * If we receive a duplicate RDMA request, it means the
-                * requester saw a sequence error and needs to restart
-                * from an earlier point.  We can abort the current
-                * RDMA read send in that case.
+                * Address range must be a subset of the original
+                * request and start on pmtu boundaries.
+                * We reuse the old ack_queue slot since the requester
+                * should not back up and request an earlier PSN for the
+                * same request.
                 */
-               spin_lock_irq(&qp->s_lock);
-               if (qp->s_ack_state != OP(ACKNOWLEDGE) &&
-                   (qp->s_hdrwords || ipath_cmp24(psn, qp->s_ack_psn) >= 0)) {
-                       /*
-                        * We are already sending earlier requested data.
-                        * Don't abort it to send later out of sequence data.
-                        */
-                       spin_unlock_irq(&qp->s_lock);
-                       goto done;
-               }
-               qp->s_rdma_len = be32_to_cpu(reth->length);
-               if (qp->s_rdma_len != 0) {
+               offset = ((psn - e->psn) & IPATH_PSN_MASK) *
+                       ib_mtu_enum_to_int(qp->path_mtu);
+               len = be32_to_cpu(reth->length);
+               if (unlikely(offset + len > e->rdma_sge.sge.sge_length))
+                       goto unlock_done;
+               if (len != 0) {
                        u32 rkey = be32_to_cpu(reth->rkey);
                        u64 vaddr = be64_to_cpu(reth->vaddr);
                        int ok;
 
-                       /*
-                        * Address range must be a subset of the original
-                        * request and start on pmtu boundaries.
-                        */
-                       ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
-                                          qp->s_rdma_len, vaddr, rkey,
+                       ok = ipath_rkey_ok(qp, &e->rdma_sge,
+                                          len, vaddr, rkey,
                                           IB_ACCESS_REMOTE_READ);
-                       if (unlikely(!ok)) {
-                               spin_unlock_irq(&qp->s_lock);
-                               goto done;
-                       }
+                       if (unlikely(!ok))
+                               goto unlock_done;
                } else {
-                       qp->s_rdma_sge.sg_list = NULL;
-                       qp->s_rdma_sge.num_sge = 0;
-                       qp->s_rdma_sge.sge.mr = NULL;
-                       qp->s_rdma_sge.sge.vaddr = NULL;
-                       qp->s_rdma_sge.sge.length = 0;
-                       qp->s_rdma_sge.sge.sge_length = 0;
+                       e->rdma_sge.sg_list = NULL;
+                       e->rdma_sge.num_sge = 0;
+                       e->rdma_sge.sge.mr = NULL;
+                       e->rdma_sge.sge.vaddr = NULL;
+                       e->rdma_sge.sge.length = 0;
+                       e->rdma_sge.sge.sge_length = 0;
                }
-               qp->s_ack_state = opcode;
-               qp->s_ack_psn = psn;
-               spin_unlock_irq(&qp->s_lock);
-               tasklet_hi_schedule(&qp->s_task);
-               goto send_ack;
+               e->psn = psn;
+               qp->s_ack_state = OP(ACKNOWLEDGE);
+               qp->s_tail_ack_queue = prev;
+               break;
        }
 
-       /*
-        * A pending RDMA read will ACK anything before it so
-        * ignore earlier duplicate requests.
-        */
-       if (qp->s_ack_state != OP(ACKNOWLEDGE))
-               goto done;
-
-       /*
-        * If an ACK is pending, don't replace the pending ACK
-        * with an earlier one since the later one will ACK the earlier.
-        * Also, if we already have a pending atomic, send it.
-        */
-       if (qp->r_ack_state != OP(ACKNOWLEDGE) &&
-           (ipath_cmp24(psn, qp->r_ack_psn) <= 0 ||
-            qp->r_ack_state >= OP(COMPARE_SWAP)))
-               goto send_ack;
-       switch (opcode) {
        case OP(COMPARE_SWAP):
-       case OP(FETCH_ADD):
+       case OP(FETCH_ADD): {
                /*
-                * Check for the PSN of the last atomic operation
-                * performed and resend the result if found.
+                * If we didn't find the atomic request in the ack queue
+                * or the send tasklet is already backed up to send an
+                * earlier entry, we can ignore this request.
                 */
-               if ((psn & IPATH_PSN_MASK) != qp->r_atomic_psn)
-                       goto done;
+               if (!e || e->opcode != (u8) opcode || old_req)
+                       goto unlock_done;
+               qp->s_ack_state = OP(ACKNOWLEDGE);
+               qp->s_tail_ack_queue = prev;
+               break;
+       }
+
+       default:
+               if (old_req)
+                       goto unlock_done;
+               /*
+                * Resend the most recent ACK if this request is
+                * after all the previous RDMA reads and atomics.
+                */
+               if (i == qp->r_head_ack_queue) {
+                       spin_unlock_irq(&qp->s_lock);
+                       qp->r_nak_state = 0;
+                       qp->r_ack_psn = qp->r_psn - 1;
+                       goto send_ack;
+               }
+               /*
+                * Resend the RDMA read or atomic op which
+                * ACKs this duplicate request.
+                */
+               qp->s_ack_state = OP(ACKNOWLEDGE);
+               qp->s_tail_ack_queue = i;
                break;
        }
-       qp->r_ack_state = opcode;
        qp->r_nak_state = 0;
-       qp->r_ack_psn = psn;
-send_ack:
-       return 0;
+       spin_unlock_irq(&qp->s_lock);
+       tasklet_hi_schedule(&qp->s_task);
 
+unlock_done:
+       spin_unlock_irq(&qp->s_lock);
 done:
        return 1;
+
+send_ack:
+       return 0;
 }
 
 static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
@@ -1391,15 +1544,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
                    opcode == OP(SEND_LAST_WITH_IMMEDIATE))
                        break;
        nack_inv:
-               /*
-                * A NAK will ACK earlier sends and RDMA writes.
-                * Don't queue the NAK if a RDMA read, atomic, or NAK
-                * is pending though.
-                */
-               if (qp->r_ack_state >= OP(COMPARE_SWAP))
-                       goto send_ack;
                ipath_rc_error(qp, IB_WC_REM_INV_REQ_ERR);
-               qp->r_ack_state = OP(SEND_ONLY);
                qp->r_nak_state = IB_NAK_INVALID_REQUEST;
                qp->r_ack_psn = qp->r_psn;
                goto send_ack;
@@ -1441,9 +1586,8 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
                         * Don't queue the NAK if a RDMA read or atomic
                         * is pending though.
                         */
-                       if (qp->r_ack_state >= OP(COMPARE_SWAP))
-                               goto send_ack;
-                       qp->r_ack_state = OP(SEND_ONLY);
+                       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;
@@ -1567,7 +1711,19 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
                        goto rnr_nak;
                goto send_last_imm;
 
-       case OP(RDMA_READ_REQUEST):
+       case OP(RDMA_READ_REQUEST): {
+               struct ipath_ack_entry *e;
+               u32 len;
+               u8 next;
+
+               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
+                       goto nack_acc;
+               next = qp->r_head_ack_queue + 1;
+               if (next > IPATH_MAX_RDMA_ATOMIC)
+                       next = 0;
+               if (unlikely(next == qp->s_tail_ack_queue))
+                       goto nack_inv;
+               e = &qp->s_ack_queue[qp->r_head_ack_queue];
                /* RETH comes after BTH */
                if (!header_in_data)
                        reth = &ohdr->u.rc.reth;
@@ -1575,72 +1731,75 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
                        reth = (struct ib_reth *)data;
                        data += sizeof(*reth);
                }
-               if (unlikely(!(qp->qp_access_flags &
-                              IB_ACCESS_REMOTE_READ)))
-                       goto nack_acc;
-               spin_lock_irq(&qp->s_lock);
-               qp->s_rdma_len = be32_to_cpu(reth->length);
-               if (qp->s_rdma_len != 0) {
+               len = be32_to_cpu(reth->length);
+               if (len) {
                        u32 rkey = be32_to_cpu(reth->rkey);
                        u64 vaddr = be64_to_cpu(reth->vaddr);
                        int ok;
 
                        /* Check rkey & NAK */
-                       ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
-                                          qp->s_rdma_len, vaddr, rkey,
-                                          IB_ACCESS_REMOTE_READ);
-                       if (unlikely(!ok)) {
-                               spin_unlock_irq(&qp->s_lock);
+                       ok = ipath_rkey_ok(qp, &e->rdma_sge, len, vaddr,
+                                          rkey, IB_ACCESS_REMOTE_READ);
+                       if (unlikely(!ok))
                                goto nack_acc;
-                       }
                        /*
                         * Update the next expected PSN.  We add 1 later
                         * below, so only add the remainder here.
                         */
-                       if (qp->s_rdma_len > pmtu)
-                               qp->r_psn += (qp->s_rdma_len - 1) / pmtu;
+                       if (len > pmtu)
+                               qp->r_psn += (len - 1) / pmtu;
                } else {
-                       qp->s_rdma_sge.sg_list = NULL;
-                       qp->s_rdma_sge.num_sge = 0;
-                       qp->s_rdma_sge.sge.mr = NULL;
-                       qp->s_rdma_sge.sge.vaddr = NULL;
-                       qp->s_rdma_sge.sge.length = 0;
-                       qp->s_rdma_sge.sge.sge_length = 0;
+                       e->rdma_sge.sg_list = NULL;
+                       e->rdma_sge.num_sge = 0;
+                       e->rdma_sge.sge.mr = NULL;
+                       e->rdma_sge.sge.vaddr = NULL;
+                       e->rdma_sge.sge.length = 0;
+                       e->rdma_sge.sge.sge_length = 0;
                }
+               e->opcode = opcode;
+               e->psn = psn;
                /*
                 * We need to increment the MSN here instead of when we
                 * finish sending the result since a duplicate request would
                 * increment it more than once.
                 */
                qp->r_msn++;
-
-               qp->s_ack_state = opcode;
-               qp->s_ack_psn = psn;
-               spin_unlock_irq(&qp->s_lock);
-
                qp->r_psn++;
                qp->r_state = opcode;
                qp->r_nak_state = 0;
+               barrier();
+               qp->r_head_ack_queue = next;
 
                /* Call ipath_do_rc_send() in another thread. */
                tasklet_hi_schedule(&qp->s_task);
 
                goto done;
+       }
 
        case OP(COMPARE_SWAP):
        case OP(FETCH_ADD): {
                struct ib_atomic_eth *ateth;
+               struct ipath_ack_entry *e;
                u64 vaddr;
+               atomic64_t *maddr;
                u64 sdata;
                u32 rkey;
+               u8 next;
 
+               if (unlikely(!(qp->qp_access_flags &
+                              IB_ACCESS_REMOTE_ATOMIC)))
+                       goto nack_acc;
+               next = qp->r_head_ack_queue + 1;
+               if (next > IPATH_MAX_RDMA_ATOMIC)
+                       next = 0;
+               if (unlikely(next == qp->s_tail_ack_queue))
+                       goto nack_inv;
                if (!header_in_data)
                        ateth = &ohdr->u.atomic_eth;
-               else {
+               else
                        ateth = (struct ib_atomic_eth *)data;
-                       data += sizeof(*ateth);
-               }
-               vaddr = be64_to_cpu(ateth->vaddr);
+               vaddr = ((u64) be32_to_cpu(ateth->vaddr[0]) << 32) |
+                       be32_to_cpu(ateth->vaddr[1]);
                if (unlikely(vaddr & (sizeof(u64) - 1)))
                        goto nack_inv;
                rkey = be32_to_cpu(ateth->rkey);
@@ -1649,63 +1808,50 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
                                            sizeof(u64), vaddr, rkey,
                                            IB_ACCESS_REMOTE_ATOMIC)))
                        goto nack_acc;
-               if (unlikely(!(qp->qp_access_flags &
-                              IB_ACCESS_REMOTE_ATOMIC)))
-                       goto nack_acc;
                /* Perform atomic OP and save result. */
+               maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
                sdata = be64_to_cpu(ateth->swap_data);
-               spin_lock_irq(&dev->pending_lock);
-               qp->r_atomic_data = *(u64 *) qp->r_sge.sge.vaddr;
-               if (opcode == OP(FETCH_ADD))
-                       *(u64 *) qp->r_sge.sge.vaddr =
-                               qp->r_atomic_data + sdata;
-               else if (qp->r_atomic_data ==
-                        be64_to_cpu(ateth->compare_data))
-                       *(u64 *) qp->r_sge.sge.vaddr = sdata;
-               spin_unlock_irq(&dev->pending_lock);
+               e = &qp->s_ack_queue[qp->r_head_ack_queue];
+               e->atomic_data = (opcode == OP(FETCH_ADD)) ?
+                       (u64) atomic64_add_return(sdata, maddr) - sdata :
+                       (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
+                                     be64_to_cpu(ateth->compare_data),
+                                     sdata);
+               e->opcode = opcode;
+               e->psn = psn & IPATH_PSN_MASK;
                qp->r_msn++;
-               qp->r_atomic_psn = psn & IPATH_PSN_MASK;
-               psn |= 1 << 31;
-               break;
+               qp->r_psn++;
+               qp->r_state = opcode;
+               qp->r_nak_state = 0;
+               barrier();
+               qp->r_head_ack_queue = next;
+
+               /* Call ipath_do_rc_send() in another thread. */
+               tasklet_hi_schedule(&qp->s_task);
+
+               goto done;
        }
 
        default:
-               /* Drop packet for unknown opcodes. */
-               goto done;
+               /* NAK unknown opcodes. */
+               goto nack_inv;
        }
        qp->r_psn++;
        qp->r_state = opcode;
+       qp->r_ack_psn = psn;
        qp->r_nak_state = 0;
        /* Send an ACK if requested or required. */
-       if (psn & (1 << 31)) {
-               /*
-                * Coalesce ACKs unless there is a RDMA READ or
-                * ATOMIC pending.
-                */
-               if (qp->r_ack_state < OP(COMPARE_SWAP)) {
-                       qp->r_ack_state = opcode;
-                       qp->r_ack_psn = psn;
-               }
+       if (psn & (1 << 31))
                goto send_ack;
-       }
        goto done;
 
 nack_acc:
-       /*
-        * A NAK will ACK earlier sends and RDMA writes.
-        * Don't queue the NAK if a RDMA read, atomic, or NAK
-        * is pending though.
-        */
-       if (qp->r_ack_state < OP(COMPARE_SWAP)) {
-               ipath_rc_error(qp, IB_WC_REM_ACCESS_ERR);
-               qp->r_ack_state = OP(RDMA_WRITE_ONLY);
-               qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
-               qp->r_ack_psn = qp->r_psn;
-       }
+       ipath_rc_error(qp, IB_WC_REM_ACCESS_ERR);
+       qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
+       qp->r_ack_psn = qp->r_psn;
+
 send_ack:
-       /* Send ACK right away unless the send tasklet has a pending ACK. */
-       if (qp->s_ack_state == OP(ACKNOWLEDGE))
-               send_rc_ack(qp);
+       send_rc_ack(qp);
 
 done:
        return;