]> err.no Git - linux-2.6/blobdiff - drivers/infiniband/hw/ipath/ipath_ruc.c
IB/ipath: Support larger IB_QP_MAX_DEST_RD_ATOMIC and IB_QP_MAX_QP_RD_ATOMIC
[linux-2.6] / drivers / infiniband / hw / ipath / ipath_ruc.c
index dd09420d677d8897a3a966f219cb130d93975843..d9c2a9b15d8686f27ae54e137ecb244ded1b3242 100644 (file)
@@ -108,7 +108,6 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
 
 static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
 {
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
        int user = to_ipd(qp->ibqp.pd)->user;
        int i, j, ret;
        struct ib_wc wc;
@@ -119,8 +118,7 @@ static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
                        continue;
                /* Check LKEY */
                if ((user && wqe->sg_list[i].lkey == 0) ||
-                   !ipath_lkey_ok(&dev->lk_table,
-                                  &qp->r_sg_list[j], &wqe->sg_list[i],
+                   !ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i],
                                   IB_ACCESS_LOCAL_WRITE))
                        goto bad_lkey;
                qp->r_len += wqe->sg_list[i].length;
@@ -139,7 +137,7 @@ bad_lkey:
        wc.vendor_err = 0;
        wc.byte_len = 0;
        wc.imm_data = 0;
-       wc.qp_num = qp->ibqp.qp_num;
+       wc.qp = &qp->ibqp;
        wc.src_qp = 0;
        wc.wc_flags = 0;
        wc.pkey_index = 0;
@@ -204,6 +202,7 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
        wq->tail = tail;
 
        ret = 1;
+       qp->r_wrid_valid = 1;
        if (handler) {
                u32 n;
 
@@ -256,6 +255,7 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp)
        unsigned long flags;
        struct ib_wc wc;
        u64 sdata;
+       atomic64_t *maddr;
 
        qp = ipath_lookup_qpn(&dev->qp_table, sqp->remote_qpn);
        if (!qp) {
@@ -266,7 +266,8 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp)
 again:
        spin_lock_irqsave(&sqp->s_lock, flags);
 
-       if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_SEND_OK)) {
+       if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_SEND_OK) ||
+           qp->s_rnr_timeout) {
                spin_unlock_irqrestore(&sqp->s_lock, flags);
                goto done;
        }
@@ -311,7 +312,7 @@ again:
                                sqp->s_rnr_retry--;
                        dev->n_rnr_naks++;
                        sqp->s_rnr_timeout =
-                               ib_ipath_rnr_table[sqp->r_min_rnr_timer];
+                               ib_ipath_rnr_table[qp->r_min_rnr_timer];
                        ipath_insert_rnr_queue(sqp);
                        goto done;
                }
@@ -326,7 +327,7 @@ again:
        case IB_WR_RDMA_WRITE:
                if (wqe->length == 0)
                        break;
-               if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, wqe->length,
+               if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length,
                                            wqe->wr.wr.rdma.remote_addr,
                                            wqe->wr.wr.rdma.rkey,
                                            IB_ACCESS_REMOTE_WRITE))) {
@@ -337,27 +338,29 @@ again:
                        wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
                        wc.vendor_err = 0;
                        wc.byte_len = 0;
-                       wc.qp_num = sqp->ibqp.qp_num;
+                       wc.qp = &sqp->ibqp;
                        wc.src_qp = sqp->remote_qpn;
                        wc.pkey_index = 0;
                        wc.slid = sqp->remote_ah_attr.dlid;
                        wc.sl = sqp->remote_ah_attr.sl;
                        wc.dlid_path_bits = 0;
                        wc.port_num = 0;
+                       spin_lock_irqsave(&sqp->s_lock, flags);
                        ipath_sqerror_qp(sqp, &wc);
+                       spin_unlock_irqrestore(&sqp->s_lock, flags);
                        goto done;
                }
                break;
 
        case IB_WR_RDMA_READ:
-               if (unlikely(!ipath_rkey_ok(dev, &sqp->s_sge, wqe->length,
+               if (unlikely(!(qp->qp_access_flags &
+                              IB_ACCESS_REMOTE_READ)))
+                       goto acc_err;
+               if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length,
                                            wqe->wr.wr.rdma.remote_addr,
                                            wqe->wr.wr.rdma.rkey,
                                            IB_ACCESS_REMOTE_READ)))
                        goto acc_err;
-               if (unlikely(!(qp->qp_access_flags &
-                              IB_ACCESS_REMOTE_READ)))
-                       goto acc_err;
                qp->r_sge.sge = wqe->sg_list[0];
                qp->r_sge.sg_list = wqe->sg_list + 1;
                qp->r_sge.num_sge = wqe->wr.num_sge;
@@ -365,22 +368,22 @@ again:
 
        case IB_WR_ATOMIC_CMP_AND_SWP:
        case IB_WR_ATOMIC_FETCH_AND_ADD:
-               if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, sizeof(u64),
-                                           wqe->wr.wr.rdma.remote_addr,
-                                           wqe->wr.wr.rdma.rkey,
+               if (unlikely(!(qp->qp_access_flags &
+                              IB_ACCESS_REMOTE_ATOMIC)))
+                       goto acc_err;
+               if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64),
+                                           wqe->wr.wr.atomic.remote_addr,
+                                           wqe->wr.wr.atomic.rkey,
                                            IB_ACCESS_REMOTE_ATOMIC)))
                        goto acc_err;
                /* Perform atomic OP and save result. */
-               sdata = wqe->wr.wr.atomic.swap;
-               spin_lock_irqsave(&dev->pending_lock, flags);
-               qp->r_atomic_data = *(u64 *) qp->r_sge.sge.vaddr;
-               if (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
-                       *(u64 *) qp->r_sge.sge.vaddr =
-                               qp->r_atomic_data + sdata;
-               else if (qp->r_atomic_data == wqe->wr.wr.atomic.compare_add)
-                       *(u64 *) qp->r_sge.sge.vaddr = sdata;
-               spin_unlock_irqrestore(&dev->pending_lock, flags);
-               *(u64 *) sqp->s_sge.sge.vaddr = qp->r_atomic_data;
+               maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
+               sdata = wqe->wr.wr.atomic.compare_add;
+               *(u64 *) sqp->s_sge.sge.vaddr =
+                       (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
+                       (u64) atomic64_add_return(sdata, maddr) - sdata :
+                       (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
+                                     sdata, wqe->wr.wr.atomic.swap);
                goto send_comp;
 
        default:
@@ -427,7 +430,7 @@ again:
        wc.status = IB_WC_SUCCESS;
        wc.vendor_err = 0;
        wc.byte_len = wqe->length;
-       wc.qp_num = qp->ibqp.qp_num;
+       wc.qp = &qp->ibqp;
        wc.src_qp = qp->remote_qpn;
        /* XXX do we know which pkey matched? Only needed for GSI. */
        wc.pkey_index = 0;
@@ -441,14 +444,14 @@ again:
 send_comp:
        sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
 
-       if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &sqp->s_flags) ||
+       if (!(sqp->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.qp_num = sqp->ibqp.qp_num;
+               wc.qp = &sqp->ibqp;
                wc.src_qp = 0;
                wc.pkey_index = 0;
                wc.slid = 0;
@@ -470,6 +473,15 @@ done:
                wake_up(&qp->wait);
 }
 
+static int want_buffer(struct ipath_devdata *dd)
+{
+       set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+                        dd->ipath_sendctrl);
+
+       return 0;
+}
+
 /**
  * ipath_no_bufs_available - tell the layer driver we need buffers
  * @qp: the QP that caused the problem
@@ -486,7 +498,7 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
                list_add_tail(&qp->piowait, &dev->piowait);
        spin_unlock_irqrestore(&dev->pending_lock, flags);
        /*
-        * Note that as soon as ipath_layer_want_buffer() is called and
+        * Note that as soon as want_buffer() is called and
         * possibly before it returns, ipath_ib_piobufavail()
         * could be called.  If we are still in the tasklet function,
         * tasklet_hi_schedule() will not call us until the next time
@@ -494,9 +506,9 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
         * We clear the tasklet flag now since we are committing to return
         * from the tasklet function.
         */
-       clear_bit(IPATH_S_BUSY, &qp->s_flags);
+       clear_bit(IPATH_S_BUSY, &qp->s_busy);
        tasklet_unlock(&qp->s_task);
-       ipath_layer_want_buffer(dev->dd);
+       want_buffer(dev->dd);
        dev->n_piowait++;
 }
 
@@ -533,6 +545,9 @@ int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
                    wr->sg_list[0].addr & (sizeof(u64) - 1))) {
                ret = -EINVAL;
                goto bail;
+       } else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) {
+               ret = -EINVAL;
+               goto bail;
        }
        /* IB spec says that num_sge == 0 is OK. */
        if (wr->num_sge > qp->s_max_sge) {
@@ -566,8 +581,7 @@ int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
                }
                if (wr->sg_list[i].length == 0)
                        continue;
-               if (!ipath_lkey_ok(&to_idev(qp->ibqp.device)->lk_table,
-                                  &wqe->sg_list[j], &wr->sg_list[i],
+               if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i],
                                   acc)) {
                        spin_unlock_irqrestore(&qp->s_lock, flags);
                        ret = -EINVAL;
@@ -611,7 +625,7 @@ u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
        hdr->hop_limit = grh->hop_limit;
        /* The SGID is 32-bit aligned. */
        hdr->sgid.global.subnet_prefix = dev->gid_prefix;
-       hdr->sgid.global.interface_id = ipath_layer_get_guid(dev->dd);
+       hdr->sgid.global.interface_id = dev->dd->ipath_guid;
        hdr->dgid = grh->dgid;
 
        /* GRH header size in 32-bit words. */
@@ -640,11 +654,10 @@ void ipath_do_ruc_send(unsigned long data)
        u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
        struct ipath_other_headers *ohdr;
 
-       if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags))
+       if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy))
                goto bail;
 
-       if (unlikely(qp->remote_ah_attr.dlid ==
-                    ipath_layer_get_lid(dev->dd))) {
+       if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) {
                ipath_ruc_loopback(qp);
                goto clear;
        }
@@ -677,19 +690,15 @@ again:
         */
        spin_lock_irqsave(&qp->s_lock, flags);
 
-       /* Sending responses has higher priority over sending requests. */
-       if (qp->s_ack_state != IB_OPCODE_RC_ACKNOWLEDGE &&
-           (bth0 = ipath_make_rc_ack(qp, ohdr, pmtu)) != 0)
-               bth2 = qp->s_ack_psn++ & IPATH_PSN_MASK;
-       else if (!((qp->ibqp.qp_type == IB_QPT_RC) ?
-                  ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) :
-                  ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) {
+       if (!((qp->ibqp.qp_type == IB_QPT_RC) ?
+              ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) :
+              ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) {
                /*
                 * Clear the busy bit before unlocking to avoid races with
                 * adding new work queue items and then failing to process
                 * them.
                 */
-               clear_bit(IPATH_S_BUSY, &qp->s_flags);
+               clear_bit(IPATH_S_BUSY, &qp->s_busy);
                spin_unlock_irqrestore(&qp->s_lock, flags);
                goto bail;
        }
@@ -711,8 +720,8 @@ again:
        qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
        qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
                                       SIZE_OF_CRC);
-       qp->s_hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd));
-       bth0 |= ipath_layer_get_pkey(dev->dd, qp->s_pkey_index);
+       qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
+       bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
        bth0 |= extra_bytes << 20;
        ohdr->bth[0] = cpu_to_be32(bth0);
        ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
@@ -722,7 +731,7 @@ again:
        goto again;
 
 clear:
-       clear_bit(IPATH_S_BUSY, &qp->s_flags);
+       clear_bit(IPATH_S_BUSY, &qp->s_busy);
 bail:
        return;
 }