IB/ipath: Add mappings from HW register to PortInfo port physical state
[safe/jmp/linux-2.6] / drivers / infiniband / hw / ipath / ipath_qp.c
index a8c4a6b..80dc623 100644 (file)
@@ -377,16 +377,18 @@ static void ipath_reset_qp(struct ipath_qp *qp)
  * @err: the receive completion error to signal if a RWQE is active
  *
  * Flushes both send and receive work queues.
+ * Returns true if last WQE event should be generated.
  * The QP s_lock should be held and interrupts disabled.
  */
 
-void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
+int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
 {
        struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
        struct ib_wc wc;
+       int ret = 0;
 
-       ipath_dbg("QP%d/%d in error state\n",
-                 qp->ibqp.qp_num, qp->remote_qpn);
+       ipath_dbg("QP%d/%d in error state (%d)\n",
+                 qp->ibqp.qp_num, qp->remote_qpn, err);
 
        spin_lock(&dev->pending_lock);
        /* XXX What if its already removed by the timeout code? */
@@ -454,7 +456,10 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
                wq->tail = tail;
 
                spin_unlock(&qp->r_rq.lock);
-       }
+       } else if (qp->ibqp.event_handler)
+               ret = 1;
+
+       return ret;
 }
 
 /**
@@ -473,6 +478,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        struct ipath_qp *qp = to_iqp(ibqp);
        enum ib_qp_state cur_state, new_state;
        unsigned long flags;
+       int lastwqe = 0;
        int ret;
 
        spin_lock_irqsave(&qp->s_lock, flags);
@@ -532,7 +538,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                break;
 
        case IB_QPS_ERR:
-               ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
+               lastwqe = ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
                break;
 
        default:
@@ -591,6 +597,14 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        qp->state = new_state;
        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);
+       }
        ret = 0;
        goto bail;
 
@@ -821,7 +835,8 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
                                      init_attr->qp_type);
                if (err) {
                        ret = ERR_PTR(err);
-                       goto bail_rwq;
+                       vfree(qp->r_rq.wq);
+                       goto bail_qp;
                }
                qp->ip = NULL;
                ipath_reset_qp(qp);
@@ -840,8 +855,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
         * See ipath_mmap() for details.
         */
        if (udata && udata->outlen >= sizeof(__u64)) {
-               int err;
-
                if (!qp->r_rq.wq) {
                        __u64 offset = 0;
 
@@ -849,7 +862,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
                                               sizeof(offset));
                        if (err) {
                                ret = ERR_PTR(err);
-                               goto bail_rwq;
+                               goto bail_ip;
                        }
                } else {
                        u32 s = sizeof(struct ipath_rwq) +
@@ -861,7 +874,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
                                                   qp->r_rq.wq);
                        if (!qp->ip) {
                                ret = ERR_PTR(-ENOMEM);
-                               goto bail_rwq;
+                               goto bail_ip;
                        }
 
                        err = ib_copy_to_udata(udata, &(qp->ip->offset),
@@ -893,9 +906,11 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
        goto bail;
 
 bail_ip:
-       kfree(qp->ip);
-bail_rwq:
-       vfree(qp->r_rq.wq);
+       if (qp->ip)
+               kref_put(&qp->ip->ref, ipath_release_mmap_info);
+       else
+               vfree(qp->r_rq.wq);
+       ipath_free_qp(&dev->qp_table, qp);
 bail_qp:
        kfree(qp);
 bail_swq: