Browse Source

Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband

* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband:
  IPoIB: Convert to NAPI
  IB: Return "maybe missed event" hint from ib_req_notify_cq()
  IB: Add CQ comp_vector support
  IB/ipath: Fix a race condition when generating ACKs
  IB/ipath: Fix two more spin lock problems
  IB/fmr_pool: Add prefix to all printks
  IB/srp: Set proc_name
  IB/srp: Add orig_dgid sysfs attribute to scsi_host
  IPoIB/cm: Don't crash if remote side uses one QP for both directions
  RDMA/cxgb3: Support for new abort logic
  RDMA/cxgb3: Initialize cpu_idx field in cpl_close_listserv_req message
  RDMA/cxgb3: Fail qp creation if the requested max_inline is too large
  RDMA/cxgb3: Fix TERM codes
  IPoIB/cm: Fix error handling in ipoib_cm_dev_open()
  IB/ipath: Don't corrupt pending mmap list when unmapped objects are freed
  IB/mthca: Work around kernel QP starvation
  IB/ipath: Don't put QP in timeout queue if waiting to send
  IB/ipath: Don't call spin_lock_irq() from interrupt context
Linus Torvalds 18 years ago
parent
commit
972d45fb43
40 changed files with 508 additions and 239 deletions
  1. 17 15
      drivers/infiniband/core/fmr_pool.c
  2. 1 1
      drivers/infiniband/core/mad.c
  3. 1 0
      drivers/infiniband/core/uverbs_cmd.c
  4. 1 1
      drivers/infiniband/core/uverbs_main.c
  5. 2 2
      drivers/infiniband/core/verbs.c
  6. 1 1
      drivers/infiniband/hw/amso1100/c2.h
  7. 12 4
      drivers/infiniband/hw/amso1100/c2_cq.c
  8. 2 1
      drivers/infiniband/hw/amso1100/c2_provider.c
  9. 3 0
      drivers/infiniband/hw/cxgb3/cxio_hal.c
  10. 1 0
      drivers/infiniband/hw/cxgb3/cxio_wr.h
  11. 19 0
      drivers/infiniband/hw/cxgb3/iwch_cm.c
  12. 6 0
      drivers/infiniband/hw/cxgb3/iwch_cm.h
  13. 10 4
      drivers/infiniband/hw/cxgb3/iwch_provider.c
  14. 38 31
      drivers/infiniband/hw/cxgb3/iwch_qp.c
  15. 1 1
      drivers/infiniband/hw/ehca/ehca_cq.c
  16. 2 2
      drivers/infiniband/hw/ehca/ehca_iverbs.h
  17. 2 1
      drivers/infiniband/hw/ehca/ehca_main.c
  18. 11 3
      drivers/infiniband/hw/ehca/ehca_reqs.c
  19. 8 0
      drivers/infiniband/hw/ehca/ipz_pt_fn.h
  20. 34 34
      drivers/infiniband/hw/ipath/ipath_cq.c
  21. 58 6
      drivers/infiniband/hw/ipath/ipath_mmap.c
  22. 30 22
      drivers/infiniband/hw/ipath/ipath_qp.c
  23. 28 27
      drivers/infiniband/hw/ipath/ipath_rc.c
  24. 26 29
      drivers/infiniband/hw/ipath/ipath_srq.c
  25. 4 0
      drivers/infiniband/hw/ipath/ipath_verbs.c
  26. 17 7
      drivers/infiniband/hw/ipath/ipath_verbs.h
  27. 7 5
      drivers/infiniband/hw/mthca/mthca_cq.c
  28. 2 2
      drivers/infiniband/hw/mthca/mthca_dev.h
  29. 2 0
      drivers/infiniband/hw/mthca/mthca_provider.c
  30. 13 0
      drivers/infiniband/hw/mthca/mthca_qp.c
  31. 1 0
      drivers/infiniband/ulp/ipoib/ipoib.h
  32. 9 5
      drivers/infiniband/ulp/ipoib/ipoib_cm.c
  33. 70 19
      drivers/infiniband/ulp/ipoib/ipoib_ib.c
  34. 2 0
      drivers/infiniband/ulp/ipoib/ipoib_main.c
  35. 1 1
      drivers/infiniband/ulp/ipoib/ipoib_verbs.c
  36. 1 1
      drivers/infiniband/ulp/iser/iser_verbs.c
  37. 25 2
      drivers/infiniband/ulp/srp/ib_srp.c
  38. 1 0
      drivers/infiniband/ulp/srp/ib_srp.h
  39. 2 2
      drivers/net/cxgb3/version.h
  40. 37 10
      include/rdma/ib_verbs.h

+ 17 - 15
drivers/infiniband/core/fmr_pool.c

@@ -43,6 +43,8 @@
 
 
 #include "core_priv.h"
 #include "core_priv.h"
 
 
+#define PFX "fmr_pool: "
+
 enum {
 enum {
 	IB_FMR_MAX_REMAPS = 32,
 	IB_FMR_MAX_REMAPS = 32,
 
 
@@ -150,7 +152,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
 
 
 #ifdef DEBUG
 #ifdef DEBUG
 		if (fmr->ref_count !=0) {
 		if (fmr->ref_count !=0) {
-			printk(KERN_WARNING "Unmapping FMR 0x%08x with ref count %d",
+			printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d",
 			       fmr, fmr->ref_count);
 			       fmr, fmr->ref_count);
 		}
 		}
 #endif
 #endif
@@ -168,7 +170,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
 
 
 	ret = ib_unmap_fmr(&fmr_list);
 	ret = ib_unmap_fmr(&fmr_list);
 	if (ret)
 	if (ret)
-		printk(KERN_WARNING "ib_unmap_fmr returned %d", ret);
+		printk(KERN_WARNING PFX "ib_unmap_fmr returned %d", ret);
 
 
 	spin_lock_irq(&pool->pool_lock);
 	spin_lock_irq(&pool->pool_lock);
 	list_splice(&unmap_list, &pool->free_list);
 	list_splice(&unmap_list, &pool->free_list);
@@ -226,20 +228,20 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd             *pd,
 	device = pd->device;
 	device = pd->device;
 	if (!device->alloc_fmr    || !device->dealloc_fmr  ||
 	if (!device->alloc_fmr    || !device->dealloc_fmr  ||
 	    !device->map_phys_fmr || !device->unmap_fmr) {
 	    !device->map_phys_fmr || !device->unmap_fmr) {
-		printk(KERN_WARNING "Device %s does not support fast memory regions",
+		printk(KERN_INFO PFX "Device %s does not support FMRs\n",
 		       device->name);
 		       device->name);
 		return ERR_PTR(-ENOSYS);
 		return ERR_PTR(-ENOSYS);
 	}
 	}
 
 
 	attr = kmalloc(sizeof *attr, GFP_KERNEL);
 	attr = kmalloc(sizeof *attr, GFP_KERNEL);
 	if (!attr) {
 	if (!attr) {
-		printk(KERN_WARNING "couldn't allocate device attr struct");
+		printk(KERN_WARNING PFX "couldn't allocate device attr struct");
 		return ERR_PTR(-ENOMEM);
 		return ERR_PTR(-ENOMEM);
 	}
 	}
 
 
 	ret = ib_query_device(device, attr);
 	ret = ib_query_device(device, attr);
 	if (ret) {
 	if (ret) {
-		printk(KERN_WARNING "couldn't query device");
+		printk(KERN_WARNING PFX "couldn't query device: %d", ret);
 		kfree(attr);
 		kfree(attr);
 		return ERR_PTR(ret);
 		return ERR_PTR(ret);
 	}
 	}
@@ -253,7 +255,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd             *pd,
 
 
 	pool = kmalloc(sizeof *pool, GFP_KERNEL);
 	pool = kmalloc(sizeof *pool, GFP_KERNEL);
 	if (!pool) {
 	if (!pool) {
-		printk(KERN_WARNING "couldn't allocate pool struct");
+		printk(KERN_WARNING PFX "couldn't allocate pool struct");
 		return ERR_PTR(-ENOMEM);
 		return ERR_PTR(-ENOMEM);
 	}
 	}
 
 
@@ -270,7 +272,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd             *pd,
 			kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket,
 			kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket,
 				GFP_KERNEL);
 				GFP_KERNEL);
 		if (!pool->cache_bucket) {
 		if (!pool->cache_bucket) {
-			printk(KERN_WARNING "Failed to allocate cache in pool");
+			printk(KERN_WARNING PFX "Failed to allocate cache in pool");
 			ret = -ENOMEM;
 			ret = -ENOMEM;
 			goto out_free_pool;
 			goto out_free_pool;
 		}
 		}
@@ -294,7 +296,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd             *pd,
 				      "ib_fmr(%s)",
 				      "ib_fmr(%s)",
 				      device->name);
 				      device->name);
 	if (IS_ERR(pool->thread)) {
 	if (IS_ERR(pool->thread)) {
-		printk(KERN_WARNING "couldn't start cleanup thread");
+		printk(KERN_WARNING PFX "couldn't start cleanup thread");
 		ret = PTR_ERR(pool->thread);
 		ret = PTR_ERR(pool->thread);
 		goto out_free_pool;
 		goto out_free_pool;
 	}
 	}
@@ -311,8 +313,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd             *pd,
 			fmr = kmalloc(sizeof *fmr + params->max_pages_per_fmr * sizeof (u64),
 			fmr = kmalloc(sizeof *fmr + params->max_pages_per_fmr * sizeof (u64),
 				      GFP_KERNEL);
 				      GFP_KERNEL);
 			if (!fmr) {
 			if (!fmr) {
-				printk(KERN_WARNING "failed to allocate fmr struct "
-				       "for FMR %d", i);
+				printk(KERN_WARNING PFX "failed to allocate fmr "
+				       "struct for FMR %d", i);
 				goto out_fail;
 				goto out_fail;
 			}
 			}
 
 
@@ -323,7 +325,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd             *pd,
 
 
 			fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr);
 			fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr);
 			if (IS_ERR(fmr->fmr)) {
 			if (IS_ERR(fmr->fmr)) {
-				printk(KERN_WARNING "fmr_create failed for FMR %d", i);
+				printk(KERN_WARNING PFX "fmr_create failed "
+				       "for FMR %d", i);
 				kfree(fmr);
 				kfree(fmr);
 				goto out_fail;
 				goto out_fail;
 			}
 			}
@@ -378,7 +381,7 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
 	}
 	}
 
 
 	if (i < pool->pool_size)
 	if (i < pool->pool_size)
-		printk(KERN_WARNING "pool still has %d regions registered",
+		printk(KERN_WARNING PFX "pool still has %d regions registered",
 		       pool->pool_size - i);
 		       pool->pool_size - i);
 
 
 	kfree(pool->cache_bucket);
 	kfree(pool->cache_bucket);
@@ -463,8 +466,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
 		list_add(&fmr->list, &pool->free_list);
 		list_add(&fmr->list, &pool->free_list);
 		spin_unlock_irqrestore(&pool->pool_lock, flags);
 		spin_unlock_irqrestore(&pool->pool_lock, flags);
 
 
-		printk(KERN_WARNING "fmr_map returns %d\n",
-		       result);
+		printk(KERN_WARNING PFX "fmr_map returns %d\n", result);
 
 
 		return ERR_PTR(result);
 		return ERR_PTR(result);
 	}
 	}
@@ -516,7 +518,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
 
 
 #ifdef DEBUG
 #ifdef DEBUG
 	if (fmr->ref_count < 0)
 	if (fmr->ref_count < 0)
-		printk(KERN_WARNING "FMR %p has ref count %d < 0",
+		printk(KERN_WARNING PFX "FMR %p has ref count %d < 0",
 		       fmr, fmr->ref_count);
 		       fmr, fmr->ref_count);
 #endif
 #endif
 
 

+ 1 - 1
drivers/infiniband/core/mad.c

@@ -2771,7 +2771,7 @@ static int ib_mad_port_open(struct ib_device *device,
 	cq_size = (IB_MAD_QP_SEND_SIZE + IB_MAD_QP_RECV_SIZE) * 2;
 	cq_size = (IB_MAD_QP_SEND_SIZE + IB_MAD_QP_RECV_SIZE) * 2;
 	port_priv->cq = ib_create_cq(port_priv->device,
 	port_priv->cq = ib_create_cq(port_priv->device,
 				     ib_mad_thread_completion_handler,
 				     ib_mad_thread_completion_handler,
-				     NULL, port_priv, cq_size);
+				     NULL, port_priv, cq_size, 0);
 	if (IS_ERR(port_priv->cq)) {
 	if (IS_ERR(port_priv->cq)) {
 		printk(KERN_ERR PFX "Couldn't create ib_mad CQ\n");
 		printk(KERN_ERR PFX "Couldn't create ib_mad CQ\n");
 		ret = PTR_ERR(port_priv->cq);
 		ret = PTR_ERR(port_priv->cq);

+ 1 - 0
drivers/infiniband/core/uverbs_cmd.c

@@ -802,6 +802,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
 	INIT_LIST_HEAD(&obj->async_list);
 	INIT_LIST_HEAD(&obj->async_list);
 
 
 	cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
 	cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
+					     cmd.comp_vector,
 					     file->ucontext, &udata);
 					     file->ucontext, &udata);
 	if (IS_ERR(cq)) {
 	if (IS_ERR(cq)) {
 		ret = PTR_ERR(cq);
 		ret = PTR_ERR(cq);

+ 1 - 1
drivers/infiniband/core/uverbs_main.c

@@ -752,7 +752,7 @@ static void ib_uverbs_add_one(struct ib_device *device)
 	spin_unlock(&map_lock);
 	spin_unlock(&map_lock);
 
 
 	uverbs_dev->ib_dev           = device;
 	uverbs_dev->ib_dev           = device;
-	uverbs_dev->num_comp_vectors = 1;
+	uverbs_dev->num_comp_vectors = device->num_comp_vectors;
 
 
 	uverbs_dev->dev = cdev_alloc();
 	uverbs_dev->dev = cdev_alloc();
 	if (!uverbs_dev->dev)
 	if (!uverbs_dev->dev)

+ 2 - 2
drivers/infiniband/core/verbs.c

@@ -609,11 +609,11 @@ EXPORT_SYMBOL(ib_destroy_qp);
 struct ib_cq *ib_create_cq(struct ib_device *device,
 struct ib_cq *ib_create_cq(struct ib_device *device,
 			   ib_comp_handler comp_handler,
 			   ib_comp_handler comp_handler,
 			   void (*event_handler)(struct ib_event *, void *),
 			   void (*event_handler)(struct ib_event *, void *),
-			   void *cq_context, int cqe)
+			   void *cq_context, int cqe, int comp_vector)
 {
 {
 	struct ib_cq *cq;
 	struct ib_cq *cq;
 
 
-	cq = device->create_cq(device, cqe, NULL, NULL);
+	cq = device->create_cq(device, cqe, comp_vector, NULL, NULL);
 
 
 	if (!IS_ERR(cq)) {
 	if (!IS_ERR(cq)) {
 		cq->device        = device;
 		cq->device        = device;

+ 1 - 1
drivers/infiniband/hw/amso1100/c2.h

@@ -519,7 +519,7 @@ extern void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq);
 extern void c2_cq_event(struct c2_dev *c2dev, u32 mq_index);
 extern void c2_cq_event(struct c2_dev *c2dev, u32 mq_index);
 extern void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index);
 extern void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index);
 extern int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
 extern int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
-extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify);
+extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
 
 
 /* CM */
 /* CM */
 extern int c2_llp_connect(struct iw_cm_id *cm_id,
 extern int c2_llp_connect(struct iw_cm_id *cm_id,

+ 12 - 4
drivers/infiniband/hw/amso1100/c2_cq.c

@@ -217,17 +217,19 @@ int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
 	return npolled;
 	return npolled;
 }
 }
 
 
-int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
 {
 {
 	struct c2_mq_shared __iomem *shared;
 	struct c2_mq_shared __iomem *shared;
 	struct c2_cq *cq;
 	struct c2_cq *cq;
+	unsigned long flags;
+	int ret = 0;
 
 
 	cq = to_c2cq(ibcq);
 	cq = to_c2cq(ibcq);
 	shared = cq->mq.peer;
 	shared = cq->mq.peer;
 
 
-	if (notify == IB_CQ_NEXT_COMP)
+	if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_NEXT_COMP)
 		writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type);
 		writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type);
-	else if (notify == IB_CQ_SOLICITED)
+	else if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
 		writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type);
 		writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type);
 	else
 	else
 		return -EINVAL;
 		return -EINVAL;
@@ -241,7 +243,13 @@ int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
 	 */
 	 */
 	readb(&shared->armed);
 	readb(&shared->armed);
 
 
-	return 0;
+	if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
+		spin_lock_irqsave(&cq->lock, flags);
+		ret = !c2_mq_empty(&cq->mq);
+		spin_unlock_irqrestore(&cq->lock, flags);
+	}
+
+	return ret;
 }
 }
 
 
 static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq)
 static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq)

+ 2 - 1
drivers/infiniband/hw/amso1100/c2_provider.c

@@ -290,7 +290,7 @@ static int c2_destroy_qp(struct ib_qp *ib_qp)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries,
+static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries, int vector,
 				  struct ib_ucontext *context,
 				  struct ib_ucontext *context,
 				  struct ib_udata *udata)
 				  struct ib_udata *udata)
 {
 {
@@ -795,6 +795,7 @@ int c2_register_device(struct c2_dev *dev)
 	memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
 	memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
 	memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6);
 	memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6);
 	dev->ibdev.phys_port_cnt = 1;
 	dev->ibdev.phys_port_cnt = 1;
+	dev->ibdev.num_comp_vectors = 1;
 	dev->ibdev.dma_device = &dev->pcidev->dev;
 	dev->ibdev.dma_device = &dev->pcidev->dev;
 	dev->ibdev.query_device = c2_query_device;
 	dev->ibdev.query_device = c2_query_device;
 	dev->ibdev.query_port = c2_query_port;
 	dev->ibdev.query_port = c2_query_port;

+ 3 - 0
drivers/infiniband/hw/cxgb3/cxio_hal.c

@@ -114,7 +114,10 @@ int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq,
 				return -EIO;
 				return -EIO;
 			}
 			}
 		}
 		}
+
+		return 1;
 	}
 	}
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 0
drivers/infiniband/hw/cxgb3/cxio_wr.h

@@ -38,6 +38,7 @@
 #include "firmware_exports.h"
 #include "firmware_exports.h"
 
 
 #define T3_MAX_SGE      4
 #define T3_MAX_SGE      4
+#define T3_MAX_INLINE	64
 
 
 #define Q_EMPTY(rptr,wptr) ((rptr)==(wptr))
 #define Q_EMPTY(rptr,wptr) ((rptr)==(wptr))
 #define Q_FULL(rptr,wptr,size_log2)  ( (((wptr)-(rptr))>>(size_log2)) && \
 #define Q_FULL(rptr,wptr,size_log2)  ( (((wptr)-(rptr))>>(size_log2)) && \

+ 19 - 0
drivers/infiniband/hw/cxgb3/iwch_cm.c

@@ -1109,6 +1109,15 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
 
 
 	PDBG("%s ep %p\n", __FUNCTION__, ep);
 	PDBG("%s ep %p\n", __FUNCTION__, ep);
 
 
+	/*
+	 * We get 2 abort replies from the HW.  The first one must
+	 * be ignored except for scribbling that we need one more.
+	 */
+	if (!(ep->flags & ABORT_REQ_IN_PROGRESS)) {
+		ep->flags |= ABORT_REQ_IN_PROGRESS;
+		return CPL_RET_BUF_DONE;
+	}
+
 	close_complete_upcall(ep);
 	close_complete_upcall(ep);
 	state_set(&ep->com, DEAD);
 	state_set(&ep->com, DEAD);
 	release_ep_resources(ep);
 	release_ep_resources(ep);
@@ -1189,6 +1198,7 @@ static int listen_stop(struct iwch_listen_ep *ep)
 	}
 	}
 	req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req));
 	req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req));
 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	req->cpu_idx = 0;
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid));
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid));
 	skb->priority = 1;
 	skb->priority = 1;
 	ep->com.tdev->send(ep->com.tdev, skb);
 	ep->com.tdev->send(ep->com.tdev, skb);
@@ -1475,6 +1485,15 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
 	int ret;
 	int ret;
 	int state;
 	int state;
 
 
+	/*
+	 * We get 2 peer aborts from the HW.  The first one must
+	 * be ignored except for scribbling that we need one more.
+	 */
+	if (!(ep->flags & PEER_ABORT_IN_PROGRESS)) {
+		ep->flags |= PEER_ABORT_IN_PROGRESS;
+		return CPL_RET_BUF_DONE;
+	}
+
 	if (is_neg_adv_abort(req->status)) {
 	if (is_neg_adv_abort(req->status)) {
 		PDBG("%s neg_adv_abort ep %p tid %d\n", __FUNCTION__, ep,
 		PDBG("%s neg_adv_abort ep %p tid %d\n", __FUNCTION__, ep,
 		     ep->hwtid);
 		     ep->hwtid);

+ 6 - 0
drivers/infiniband/hw/cxgb3/iwch_cm.h

@@ -143,6 +143,11 @@ enum iwch_ep_state {
 	DEAD,
 	DEAD,
 };
 };
 
 
+enum iwch_ep_flags {
+	PEER_ABORT_IN_PROGRESS	= (1 << 0),
+	ABORT_REQ_IN_PROGRESS	= (1 << 1),
+};
+
 struct iwch_ep_common {
 struct iwch_ep_common {
 	struct iw_cm_id *cm_id;
 	struct iw_cm_id *cm_id;
 	struct iwch_qp *qp;
 	struct iwch_qp *qp;
@@ -181,6 +186,7 @@ struct iwch_ep {
 	u16 plen;
 	u16 plen;
 	u32 ird;
 	u32 ird;
 	u32 ord;
 	u32 ord;
+	u32 flags;
 };
 };
 
 
 static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id)
 static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id)

+ 10 - 4
drivers/infiniband/hw/cxgb3/iwch_provider.c

@@ -139,7 +139,7 @@ static int iwch_destroy_cq(struct ib_cq *ib_cq)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries,
+static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int vector,
 			     struct ib_ucontext *ib_context,
 			     struct ib_ucontext *ib_context,
 			     struct ib_udata *udata)
 			     struct ib_udata *udata)
 {
 {
@@ -292,7 +292,7 @@ static int iwch_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
 #endif
 #endif
 }
 }
 
 
-static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
 {
 {
 	struct iwch_dev *rhp;
 	struct iwch_dev *rhp;
 	struct iwch_cq *chp;
 	struct iwch_cq *chp;
@@ -303,7 +303,7 @@ static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
 
 
 	chp = to_iwch_cq(ibcq);
 	chp = to_iwch_cq(ibcq);
 	rhp = chp->rhp;
 	rhp = chp->rhp;
-	if (notify == IB_CQ_SOLICITED)
+	if ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
 		cq_op = CQ_ARM_SE;
 		cq_op = CQ_ARM_SE;
 	else
 	else
 		cq_op = CQ_ARM_AN;
 		cq_op = CQ_ARM_AN;
@@ -317,9 +317,11 @@ static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
 	PDBG("%s rptr 0x%x\n", __FUNCTION__, chp->cq.rptr);
 	PDBG("%s rptr 0x%x\n", __FUNCTION__, chp->cq.rptr);
 	err = cxio_hal_cq_op(&rhp->rdev, &chp->cq, cq_op, 0);
 	err = cxio_hal_cq_op(&rhp->rdev, &chp->cq, cq_op, 0);
 	spin_unlock_irqrestore(&chp->lock, flag);
 	spin_unlock_irqrestore(&chp->lock, flag);
-	if (err)
+	if (err < 0)
 		printk(KERN_ERR MOD "Error %d rearming CQID 0x%x\n", err,
 		printk(KERN_ERR MOD "Error %d rearming CQID 0x%x\n", err,
 		       chp->cq.cqid);
 		       chp->cq.cqid);
+	if (err > 0 && !(flags & IB_CQ_REPORT_MISSED_EVENTS))
+		err = 0;
 	return err;
 	return err;
 }
 }
 
 
@@ -780,6 +782,9 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd,
 	if (rqsize > T3_MAX_RQ_SIZE)
 	if (rqsize > T3_MAX_RQ_SIZE)
 		return ERR_PTR(-EINVAL);
 		return ERR_PTR(-EINVAL);
 
 
+	if (attrs->cap.max_inline_data > T3_MAX_INLINE)
+		return ERR_PTR(-EINVAL);
+
 	/*
 	/*
 	 * NOTE: The SQ and total WQ sizes don't need to be
 	 * NOTE: The SQ and total WQ sizes don't need to be
 	 * a power of two.  However, all the code assumes
 	 * a power of two.  However, all the code assumes
@@ -1107,6 +1112,7 @@ int iwch_register_device(struct iwch_dev *dev)
 	dev->ibdev.node_type = RDMA_NODE_RNIC;
 	dev->ibdev.node_type = RDMA_NODE_RNIC;
 	memcpy(dev->ibdev.node_desc, IWCH_NODE_DESC, sizeof(IWCH_NODE_DESC));
 	memcpy(dev->ibdev.node_desc, IWCH_NODE_DESC, sizeof(IWCH_NODE_DESC));
 	dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports;
 	dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports;
+	dev->ibdev.num_comp_vectors = 1;
 	dev->ibdev.dma_device = &(dev->rdev.rnic_info.pdev->dev);
 	dev->ibdev.dma_device = &(dev->rdev.rnic_info.pdev->dev);
 	dev->ibdev.query_device = iwch_query_device;
 	dev->ibdev.query_device = iwch_query_device;
 	dev->ibdev.query_port = iwch_query_port;
 	dev->ibdev.query_port = iwch_query_port;

+ 38 - 31
drivers/infiniband/hw/cxgb3/iwch_qp.c

@@ -471,43 +471,62 @@ int iwch_bind_mw(struct ib_qp *qp,
 	return err;
 	return err;
 }
 }
 
 
-static void build_term_codes(int t3err, u8 *layer_type, u8 *ecode, int tagged)
+static inline void build_term_codes(struct respQ_msg_t *rsp_msg,
+				    u8 *layer_type, u8 *ecode)
 {
 {
-	switch (t3err) {
+	int status = TPT_ERR_INTERNAL_ERR;
+	int tagged = 0;
+	int opcode = -1;
+	int rqtype = 0;
+	int send_inv = 0;
+
+	if (rsp_msg) {
+		status = CQE_STATUS(rsp_msg->cqe);
+		opcode = CQE_OPCODE(rsp_msg->cqe);
+		rqtype = RQ_TYPE(rsp_msg->cqe);
+		send_inv = (opcode == T3_SEND_WITH_INV) ||
+		           (opcode == T3_SEND_WITH_SE_INV);
+		tagged = (opcode == T3_RDMA_WRITE) ||
+			 (rqtype && (opcode == T3_READ_RESP));
+	}
+
+	switch (status) {
 	case TPT_ERR_STAG:
 	case TPT_ERR_STAG:
-		if (tagged == 1) {
-			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
-			*ecode = DDPT_INV_STAG;
-		} else if (tagged == 2) {
+		if (send_inv) {
+			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+			*ecode = RDMAP_CANT_INV_STAG;
+		} else {
 			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
 			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
 			*ecode = RDMAP_INV_STAG;
 			*ecode = RDMAP_INV_STAG;
 		}
 		}
 		break;
 		break;
 	case TPT_ERR_PDID:
 	case TPT_ERR_PDID:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		if ((opcode == T3_SEND_WITH_INV) ||
+		    (opcode == T3_SEND_WITH_SE_INV))
+			*ecode = RDMAP_CANT_INV_STAG;
+		else
+			*ecode = RDMAP_STAG_NOT_ASSOC;
+		break;
 	case TPT_ERR_QPID:
 	case TPT_ERR_QPID:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		*ecode = RDMAP_STAG_NOT_ASSOC;
+		break;
 	case TPT_ERR_ACCESS:
 	case TPT_ERR_ACCESS:
-		if (tagged == 1) {
-			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
-			*ecode = DDPT_STAG_NOT_ASSOC;
-		} else if (tagged == 2) {
-			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
-			*ecode = RDMAP_STAG_NOT_ASSOC;
-		}
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		*ecode = RDMAP_ACC_VIOL;
 		break;
 		break;
 	case TPT_ERR_WRAP:
 	case TPT_ERR_WRAP:
 		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
 		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
 		*ecode = RDMAP_TO_WRAP;
 		*ecode = RDMAP_TO_WRAP;
 		break;
 		break;
 	case TPT_ERR_BOUND:
 	case TPT_ERR_BOUND:
-		if (tagged == 1) {
+		if (tagged) {
 			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
 			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
 			*ecode = DDPT_BASE_BOUNDS;
 			*ecode = DDPT_BASE_BOUNDS;
-		} else if (tagged == 2) {
+		} else {
 			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
 			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
 			*ecode = RDMAP_BASE_BOUNDS;
 			*ecode = RDMAP_BASE_BOUNDS;
-		} else {
-			*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
-			*ecode = DDPU_MSG_TOOBIG;
 		}
 		}
 		break;
 		break;
 	case TPT_ERR_INVALIDATE_SHARED_MR:
 	case TPT_ERR_INVALIDATE_SHARED_MR:
@@ -591,8 +610,6 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)
 {
 {
 	union t3_wr *wqe;
 	union t3_wr *wqe;
 	struct terminate_message *term;
 	struct terminate_message *term;
-	int status;
-	int tagged = 0;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 
 
 	PDBG("%s %d\n", __FUNCTION__, __LINE__);
 	PDBG("%s %d\n", __FUNCTION__, __LINE__);
@@ -610,17 +627,7 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)
 
 
 	/* immediate data starts here. */
 	/* immediate data starts here. */
 	term = (struct terminate_message *)wqe->send.sgl;
 	term = (struct terminate_message *)wqe->send.sgl;
-	if (rsp_msg) {
-		status = CQE_STATUS(rsp_msg->cqe);
-		if (CQE_OPCODE(rsp_msg->cqe) == T3_RDMA_WRITE)
-			tagged = 1;
-		if ((CQE_OPCODE(rsp_msg->cqe) == T3_READ_REQ) ||
-		    (CQE_OPCODE(rsp_msg->cqe) == T3_READ_RESP))
-			tagged = 2;
-	} else {
-		status = TPT_ERR_INTERNAL_ERR;
-	}
-	build_term_codes(status, &term->layer_etype, &term->ecode, tagged);
+	build_term_codes(rsp_msg, &term->layer_etype, &term->ecode);
 	build_fw_riwrh((void *)wqe, T3_WR_SEND,
 	build_fw_riwrh((void *)wqe, T3_WR_SEND,
 		       T3_COMPLETION_FLAG | T3_NOTIFY_FLAG, 1,
 		       T3_COMPLETION_FLAG | T3_NOTIFY_FLAG, 1,
 		       qhp->ep->hwtid, 5);
 		       qhp->ep->hwtid, 5);

+ 1 - 1
drivers/infiniband/hw/ehca/ehca_cq.c

@@ -113,7 +113,7 @@ struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
 	return ret;
 	return ret;
 }
 }
 
 
-struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
 			     struct ib_ucontext *context,
 			     struct ib_ucontext *context,
 			     struct ib_udata *udata)
 			     struct ib_udata *udata)
 {
 {

+ 2 - 2
drivers/infiniband/hw/ehca/ehca_iverbs.h

@@ -123,7 +123,7 @@ int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq);
 void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq);
 void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq);
 
 
 
 
-struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
 			     struct ib_ucontext *context,
 			     struct ib_ucontext *context,
 			     struct ib_udata *udata);
 			     struct ib_udata *udata);
 
 
@@ -135,7 +135,7 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc);
 
 
 int ehca_peek_cq(struct ib_cq *cq, int wc_cnt);
 int ehca_peek_cq(struct ib_cq *cq, int wc_cnt);
 
 
-int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify);
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags);
 
 
 struct ib_qp *ehca_create_qp(struct ib_pd *pd,
 struct ib_qp *ehca_create_qp(struct ib_pd *pd,
 			     struct ib_qp_init_attr *init_attr,
 			     struct ib_qp_init_attr *init_attr,

+ 2 - 1
drivers/infiniband/hw/ehca/ehca_main.c

@@ -313,6 +313,7 @@ int ehca_init_device(struct ehca_shca *shca)
 
 
 	shca->ib_device.node_type           = RDMA_NODE_IB_CA;
 	shca->ib_device.node_type           = RDMA_NODE_IB_CA;
 	shca->ib_device.phys_port_cnt       = shca->num_ports;
 	shca->ib_device.phys_port_cnt       = shca->num_ports;
+	shca->ib_device.num_comp_vectors    = 1;
 	shca->ib_device.dma_device          = &shca->ibmebus_dev->ofdev.dev;
 	shca->ib_device.dma_device          = &shca->ibmebus_dev->ofdev.dev;
 	shca->ib_device.query_device        = ehca_query_device;
 	shca->ib_device.query_device        = ehca_query_device;
 	shca->ib_device.query_port          = ehca_query_port;
 	shca->ib_device.query_port          = ehca_query_port;
@@ -375,7 +376,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
 		return -EPERM;
 		return -EPERM;
 	}
 	}
 
 
-	ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10);
+	ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0);
 	if (IS_ERR(ibcq)) {
 	if (IS_ERR(ibcq)) {
 		ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
 		ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
 		return PTR_ERR(ibcq);
 		return PTR_ERR(ibcq);

+ 11 - 3
drivers/infiniband/hw/ehca/ehca_reqs.c

@@ -634,11 +634,13 @@ poll_cq_exit0:
 	return ret;
 	return ret;
 }
 }
 
 
-int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify)
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags)
 {
 {
 	struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
 	struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
+	unsigned long spl_flags;
+	int ret = 0;
 
 
-	switch (cq_notify) {
+	switch (notify_flags & IB_CQ_SOLICITED_MASK) {
 	case IB_CQ_SOLICITED:
 	case IB_CQ_SOLICITED:
 		hipz_set_cqx_n0(my_cq, 1);
 		hipz_set_cqx_n0(my_cq, 1);
 		break;
 		break;
@@ -649,5 +651,11 @@ int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify)
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	return 0;
+	if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
+		spin_lock_irqsave(&my_cq->spinlock, spl_flags);
+		ret = ipz_qeit_is_valid(&my_cq->ipz_queue);
+		spin_unlock_irqrestore(&my_cq->spinlock, spl_flags);
+	}
+
+	return ret;
 }
 }

+ 8 - 0
drivers/infiniband/hw/ehca/ipz_pt_fn.h

@@ -140,6 +140,14 @@ static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
 	return cqe;
 	return cqe;
 }
 }
 
 
+static inline int ipz_qeit_is_valid(struct ipz_queue *queue)
+{
+	struct ehca_cqe *cqe = ipz_qeit_get(queue);
+	u32 cqe_flags = cqe->cqe_flags;
+
+	return cqe_flags >> 7 == (queue->toggle_state & 1);
+}
+
 /*
 /*
  * returns and resets Queue Entry iterator
  * returns and resets Queue Entry iterator
  * returns address (kv) of first Queue Entry
  * returns address (kv) of first Queue Entry

+ 34 - 34
drivers/infiniband/hw/ipath/ipath_cq.c

@@ -204,7 +204,7 @@ static void send_complete(unsigned long data)
  *
  *
  * Called by ib_create_cq() in the generic verbs code.
  * Called by ib_create_cq() in the generic verbs code.
  */
  */
-struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
+struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
 			      struct ib_ucontext *context,
 			      struct ib_ucontext *context,
 			      struct ib_udata *udata)
 			      struct ib_udata *udata)
 {
 {
@@ -243,33 +243,21 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
 	 * See ipath_mmap() for details.
 	 * See ipath_mmap() for details.
 	 */
 	 */
 	if (udata && udata->outlen >= sizeof(__u64)) {
 	if (udata && udata->outlen >= sizeof(__u64)) {
-		struct ipath_mmap_info *ip;
-		__u64 offset = (__u64) wc;
 		int err;
 		int err;
+		u32 s = sizeof *wc + sizeof(struct ib_wc) * entries;
 
 
-		err = ib_copy_to_udata(udata, &offset, sizeof(offset));
-		if (err) {
-			ret = ERR_PTR(err);
+		cq->ip = ipath_create_mmap_info(dev, s, context, wc);
+		if (!cq->ip) {
+			ret = ERR_PTR(-ENOMEM);
 			goto bail_wc;
 			goto bail_wc;
 		}
 		}
 
 
-		/* Allocate info for ipath_mmap(). */
-		ip = kmalloc(sizeof(*ip), GFP_KERNEL);
-		if (!ip) {
-			ret = ERR_PTR(-ENOMEM);
-			goto bail_wc;
+		err = ib_copy_to_udata(udata, &cq->ip->offset,
+				       sizeof(cq->ip->offset));
+		if (err) {
+			ret = ERR_PTR(err);
+			goto bail_ip;
 		}
 		}
-		cq->ip = ip;
-		ip->context = context;
-		ip->obj = wc;
-		kref_init(&ip->ref);
-		ip->mmap_cnt = 0;
-		ip->size = PAGE_ALIGN(sizeof(*wc) +
-				      sizeof(struct ib_wc) * entries);
-		spin_lock_irq(&dev->pending_lock);
-		ip->next = dev->pending_mmaps;
-		dev->pending_mmaps = ip;
-		spin_unlock_irq(&dev->pending_lock);
 	} else
 	} else
 		cq->ip = NULL;
 		cq->ip = NULL;
 
 
@@ -277,12 +265,18 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
 	if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
 	if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
 		spin_unlock(&dev->n_cqs_lock);
 		spin_unlock(&dev->n_cqs_lock);
 		ret = ERR_PTR(-ENOMEM);
 		ret = ERR_PTR(-ENOMEM);
-		goto bail_wc;
+		goto bail_ip;
 	}
 	}
 
 
 	dev->n_cqs_allocated++;
 	dev->n_cqs_allocated++;
 	spin_unlock(&dev->n_cqs_lock);
 	spin_unlock(&dev->n_cqs_lock);
 
 
+	if (cq->ip) {
+		spin_lock_irq(&dev->pending_lock);
+		list_add(&cq->ip->pending_mmaps, &dev->pending_mmaps);
+		spin_unlock_irq(&dev->pending_lock);
+	}
+
 	/*
 	/*
 	 * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.
 	 * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.
 	 * The number of entries should be >= the number requested or return
 	 * The number of entries should be >= the number requested or return
@@ -301,12 +295,12 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
 
 
 	goto done;
 	goto done;
 
 
+bail_ip:
+	kfree(cq->ip);
 bail_wc:
 bail_wc:
 	vfree(wc);
 	vfree(wc);
-
 bail_cq:
 bail_cq:
 	kfree(cq);
 	kfree(cq);
-
 done:
 done:
 	return ret;
 	return ret;
 }
 }
@@ -340,17 +334,18 @@ int ipath_destroy_cq(struct ib_cq *ibcq)
 /**
 /**
  * ipath_req_notify_cq - change the notification type for a completion queue
  * ipath_req_notify_cq - change the notification type for a completion queue
  * @ibcq: the completion queue
  * @ibcq: the completion queue
- * @notify: the type of notification to request
+ * @notify_flags: the type of notification to request
  *
  *
  * Returns 0 for success.
  * Returns 0 for success.
  *
  *
  * This may be called from interrupt context.  Also called by
  * This may be called from interrupt context.  Also called by
  * ib_req_notify_cq() in the generic verbs code.
  * ib_req_notify_cq() in the generic verbs code.
  */
  */
-int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
 {
 {
 	struct ipath_cq *cq = to_icq(ibcq);
 	struct ipath_cq *cq = to_icq(ibcq);
 	unsigned long flags;
 	unsigned long flags;
+	int ret = 0;
 
 
 	spin_lock_irqsave(&cq->lock, flags);
 	spin_lock_irqsave(&cq->lock, flags);
 	/*
 	/*
@@ -358,9 +353,15 @@ int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
 	 * any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2).
 	 * any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2).
 	 */
 	 */
 	if (cq->notify != IB_CQ_NEXT_COMP)
 	if (cq->notify != IB_CQ_NEXT_COMP)
-		cq->notify = notify;
+		cq->notify = notify_flags & IB_CQ_SOLICITED_MASK;
+
+	if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
+	    cq->queue->head != cq->queue->tail)
+		ret = 1;
+
 	spin_unlock_irqrestore(&cq->lock, flags);
 	spin_unlock_irqrestore(&cq->lock, flags);
-	return 0;
+
+	return ret;
 }
 }
 
 
 /**
 /**
@@ -443,13 +444,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
 	if (cq->ip) {
 	if (cq->ip) {
 		struct ipath_ibdev *dev = to_idev(ibcq->device);
 		struct ipath_ibdev *dev = to_idev(ibcq->device);
 		struct ipath_mmap_info *ip = cq->ip;
 		struct ipath_mmap_info *ip = cq->ip;
+		u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe;
 
 
-		ip->obj = wc;
-		ip->size = PAGE_ALIGN(sizeof(*wc) +
-				      sizeof(struct ib_wc) * cqe);
+		ipath_update_mmap_info(dev, ip, s, wc);
 		spin_lock_irq(&dev->pending_lock);
 		spin_lock_irq(&dev->pending_lock);
-		ip->next = dev->pending_mmaps;
-		dev->pending_mmaps = ip;
+		if (list_empty(&ip->pending_mmaps))
+			list_add(&ip->pending_mmaps, &dev->pending_mmaps);
 		spin_unlock_irq(&dev->pending_lock);
 		spin_unlock_irq(&dev->pending_lock);
 	}
 	}
 
 

+ 58 - 6
drivers/infiniband/hw/ipath/ipath_mmap.c

@@ -46,6 +46,11 @@ void ipath_release_mmap_info(struct kref *ref)
 {
 {
 	struct ipath_mmap_info *ip =
 	struct ipath_mmap_info *ip =
 		container_of(ref, struct ipath_mmap_info, ref);
 		container_of(ref, struct ipath_mmap_info, ref);
+	struct ipath_ibdev *dev = to_idev(ip->context->device);
+
+	spin_lock_irq(&dev->pending_lock);
+	list_del(&ip->pending_mmaps);
+	spin_unlock_irq(&dev->pending_lock);
 
 
 	vfree(ip->obj);
 	vfree(ip->obj);
 	kfree(ip);
 	kfree(ip);
@@ -60,14 +65,12 @@ static void ipath_vma_open(struct vm_area_struct *vma)
 	struct ipath_mmap_info *ip = vma->vm_private_data;
 	struct ipath_mmap_info *ip = vma->vm_private_data;
 
 
 	kref_get(&ip->ref);
 	kref_get(&ip->ref);
-	ip->mmap_cnt++;
 }
 }
 
 
 static void ipath_vma_close(struct vm_area_struct *vma)
 static void ipath_vma_close(struct vm_area_struct *vma)
 {
 {
 	struct ipath_mmap_info *ip = vma->vm_private_data;
 	struct ipath_mmap_info *ip = vma->vm_private_data;
 
 
-	ip->mmap_cnt--;
 	kref_put(&ip->ref, ipath_release_mmap_info);
 	kref_put(&ip->ref, ipath_release_mmap_info);
 }
 }
 
 
@@ -87,7 +90,7 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 	struct ipath_ibdev *dev = to_idev(context->device);
 	struct ipath_ibdev *dev = to_idev(context->device);
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	unsigned long size = vma->vm_end - vma->vm_start;
 	unsigned long size = vma->vm_end - vma->vm_start;
-	struct ipath_mmap_info *ip, **pp;
+	struct ipath_mmap_info *ip, *pp;
 	int ret = -EINVAL;
 	int ret = -EINVAL;
 
 
 	/*
 	/*
@@ -96,15 +99,16 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 	 * CQ, QP, or SRQ is soon followed by a call to mmap().
 	 * CQ, QP, or SRQ is soon followed by a call to mmap().
 	 */
 	 */
 	spin_lock_irq(&dev->pending_lock);
 	spin_lock_irq(&dev->pending_lock);
-	for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) {
+	list_for_each_entry_safe(ip, pp, &dev->pending_mmaps,
+				 pending_mmaps) {
 		/* Only the creator is allowed to mmap the object */
 		/* Only the creator is allowed to mmap the object */
-		if (context != ip->context || (void *) offset != ip->obj)
+		if (context != ip->context || (__u64) offset != ip->offset)
 			continue;
 			continue;
 		/* Don't allow a mmap larger than the object. */
 		/* Don't allow a mmap larger than the object. */
 		if (size > ip->size)
 		if (size > ip->size)
 			break;
 			break;
 
 
-		*pp = ip->next;
+		list_del_init(&ip->pending_mmaps);
 		spin_unlock_irq(&dev->pending_lock);
 		spin_unlock_irq(&dev->pending_lock);
 
 
 		ret = remap_vmalloc_range(vma, ip->obj, 0);
 		ret = remap_vmalloc_range(vma, ip->obj, 0);
@@ -119,3 +123,51 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 done:
 done:
 	return ret;
 	return ret;
 }
 }
+
+/*
+ * Allocate information for ipath_mmap
+ */
+struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
+					       u32 size,
+					       struct ib_ucontext *context,
+					       void *obj) {
+	struct ipath_mmap_info *ip;
+
+	ip = kmalloc(sizeof *ip, GFP_KERNEL);
+	if (!ip)
+		goto bail;
+
+	size = PAGE_ALIGN(size);
+
+	spin_lock_irq(&dev->mmap_offset_lock);
+	if (dev->mmap_offset == 0)
+		dev->mmap_offset = PAGE_SIZE;
+	ip->offset = dev->mmap_offset;
+	dev->mmap_offset += size;
+	spin_unlock_irq(&dev->mmap_offset_lock);
+
+	INIT_LIST_HEAD(&ip->pending_mmaps);
+	ip->size = size;
+	ip->context = context;
+	ip->obj = obj;
+	kref_init(&ip->ref);
+
+bail:
+	return ip;
+}
+
+void ipath_update_mmap_info(struct ipath_ibdev *dev,
+			    struct ipath_mmap_info *ip,
+			    u32 size, void *obj) {
+	size = PAGE_ALIGN(size);
+
+	spin_lock_irq(&dev->mmap_offset_lock);
+	if (dev->mmap_offset == 0)
+		dev->mmap_offset = PAGE_SIZE;
+	ip->offset = dev->mmap_offset;
+	dev->mmap_offset += size;
+	spin_unlock_irq(&dev->mmap_offset_lock);
+
+	ip->size = size;
+	ip->obj = obj;
+}

+ 30 - 22
drivers/infiniband/hw/ipath/ipath_qp.c

@@ -844,34 +844,36 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
 	 * See ipath_mmap() for details.
 	 * See ipath_mmap() for details.
 	 */
 	 */
 	if (udata && udata->outlen >= sizeof(__u64)) {
 	if (udata && udata->outlen >= sizeof(__u64)) {
-		struct ipath_mmap_info *ip;
-		__u64 offset = (__u64) qp->r_rq.wq;
 		int err;
 		int err;
 
 
-		err = ib_copy_to_udata(udata, &offset, sizeof(offset));
-		if (err) {
-			ret = ERR_PTR(err);
-			goto bail_rwq;
-		}
+		if (!qp->r_rq.wq) {
+			__u64 offset = 0;
 
 
-		if (qp->r_rq.wq) {
-			/* Allocate info for ipath_mmap(). */
-			ip = kmalloc(sizeof(*ip), GFP_KERNEL);
-			if (!ip) {
+			err = ib_copy_to_udata(udata, &offset,
+					       sizeof(offset));
+			if (err) {
+				ret = ERR_PTR(err);
+				goto bail_rwq;
+			}
+		} else {
+			u32 s = sizeof(struct ipath_rwq) +
+				qp->r_rq.size * sz;
+
+			qp->ip =
+			    ipath_create_mmap_info(dev, s,
+						   ibpd->uobject->context,
+						   qp->r_rq.wq);
+			if (!qp->ip) {
 				ret = ERR_PTR(-ENOMEM);
 				ret = ERR_PTR(-ENOMEM);
 				goto bail_rwq;
 				goto bail_rwq;
 			}
 			}
-			qp->ip = ip;
-			ip->context = ibpd->uobject->context;
-			ip->obj = qp->r_rq.wq;
-			kref_init(&ip->ref);
-			ip->mmap_cnt = 0;
-			ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
-					      qp->r_rq.size * sz);
-			spin_lock_irq(&dev->pending_lock);
-			ip->next = dev->pending_mmaps;
-			dev->pending_mmaps = ip;
-			spin_unlock_irq(&dev->pending_lock);
+
+			err = ib_copy_to_udata(udata, &(qp->ip->offset),
+					       sizeof(qp->ip->offset));
+			if (err) {
+				ret = ERR_PTR(err);
+				goto bail_ip;
+			}
 		}
 		}
 	}
 	}
 
 
@@ -885,6 +887,12 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
 	dev->n_qps_allocated++;
 	dev->n_qps_allocated++;
 	spin_unlock(&dev->n_qps_lock);
 	spin_unlock(&dev->n_qps_lock);
 
 
+	if (qp->ip) {
+		spin_lock_irq(&dev->pending_lock);
+		list_add(&qp->ip->pending_mmaps, &dev->pending_mmaps);
+		spin_unlock_irq(&dev->pending_lock);
+	}
+
 	ret = &qp->ibqp;
 	ret = &qp->ibqp;
 	goto bail;
 	goto bail;
 
 

+ 28 - 27
drivers/infiniband/hw/ipath/ipath_rc.c

@@ -98,13 +98,21 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
 	case OP(RDMA_READ_RESPONSE_LAST):
 	case OP(RDMA_READ_RESPONSE_LAST):
 	case OP(RDMA_READ_RESPONSE_ONLY):
 	case OP(RDMA_READ_RESPONSE_ONLY):
 	case OP(ATOMIC_ACKNOWLEDGE):
 	case OP(ATOMIC_ACKNOWLEDGE):
-		qp->s_ack_state = OP(ACKNOWLEDGE);
+		/*
+		 * We can increment the tail pointer now that the last
+		 * response has been sent instead of only being
+		 * constructed.
+		 */
+		if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC)
+			qp->s_tail_ack_queue = 0;
 		/* FALLTHROUGH */
 		/* FALLTHROUGH */
+	case OP(SEND_ONLY):
 	case OP(ACKNOWLEDGE):
 	case OP(ACKNOWLEDGE):
 		/* Check for no next entry in the queue. */
 		/* Check for no next entry in the queue. */
 		if (qp->r_head_ack_queue == qp->s_tail_ack_queue) {
 		if (qp->r_head_ack_queue == qp->s_tail_ack_queue) {
 			if (qp->s_flags & IPATH_S_ACK_PENDING)
 			if (qp->s_flags & IPATH_S_ACK_PENDING)
 				goto normal;
 				goto normal;
+			qp->s_ack_state = OP(ACKNOWLEDGE);
 			goto bail;
 			goto bail;
 		}
 		}
 
 
@@ -117,12 +125,8 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
 			if (len > pmtu) {
 			if (len > pmtu) {
 				len = pmtu;
 				len = pmtu;
 				qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
 				qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
-			} else {
+			} else
 				qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
 				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);
 			ohdr->u.aeth = ipath_compute_aeth(qp);
 			hwords++;
 			hwords++;
 			qp->s_ack_rdma_psn = e->psn;
 			qp->s_ack_rdma_psn = e->psn;
@@ -139,8 +143,6 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
 				cpu_to_be32(e->atomic_data);
 				cpu_to_be32(e->atomic_data);
 			hwords += sizeof(ohdr->u.at) / sizeof(u32);
 			hwords += sizeof(ohdr->u.at) / sizeof(u32);
 			bth2 = e->psn;
 			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;
 		bth0 = qp->s_ack_state << 24;
 		break;
 		break;
@@ -156,8 +158,6 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
 			ohdr->u.aeth = ipath_compute_aeth(qp);
 			ohdr->u.aeth = ipath_compute_aeth(qp);
 			hwords++;
 			hwords++;
 			qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
 			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;
 		}
 		}
 		bth0 = qp->s_ack_state << 24;
 		bth0 = qp->s_ack_state << 24;
 		bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
 		bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
@@ -171,7 +171,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
 		 * the ACK before setting s_ack_state to ACKNOWLEDGE
 		 * the ACK before setting s_ack_state to ACKNOWLEDGE
 		 * (see above).
 		 * (see above).
 		 */
 		 */
-		qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE);
+		qp->s_ack_state = OP(SEND_ONLY);
 		qp->s_flags &= ~IPATH_S_ACK_PENDING;
 		qp->s_flags &= ~IPATH_S_ACK_PENDING;
 		qp->s_cur_sge = NULL;
 		qp->s_cur_sge = NULL;
 		if (qp->s_nak_state)
 		if (qp->s_nak_state)
@@ -223,23 +223,18 @@ int ipath_make_rc_req(struct ipath_qp *qp,
 	/* Sending responses has higher priority over sending requests. */
 	/* Sending responses has higher priority over sending requests. */
 	if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
 	if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
 	     (qp->s_flags & IPATH_S_ACK_PENDING) ||
 	     (qp->s_flags & IPATH_S_ACK_PENDING) ||
-	     qp->s_ack_state != IB_OPCODE_RC_ACKNOWLEDGE) &&
+	     qp->s_ack_state != OP(ACKNOWLEDGE)) &&
 	    ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
 	    ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
 		goto done;
 		goto done;
 
 
 	if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
 	if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
-	    qp->s_rnr_timeout)
+	    qp->s_rnr_timeout || qp->s_wait_credit)
 		goto bail;
 		goto bail;
 
 
 	/* Limit the number of packets sent without an ACK. */
 	/* Limit the number of packets sent without an ACK. */
 	if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) {
 	if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) {
 		qp->s_wait_credit = 1;
 		qp->s_wait_credit = 1;
 		dev->n_rc_stalls++;
 		dev->n_rc_stalls++;
-		spin_lock(&dev->pending_lock);
-		if (list_empty(&qp->timerwait))
-			list_add_tail(&qp->timerwait,
-				      &dev->pending[dev->pending_index]);
-		spin_unlock(&dev->pending_lock);
 		goto bail;
 		goto bail;
 	}
 	}
 
 
@@ -587,9 +582,12 @@ static void send_rc_ack(struct ipath_qp *qp)
 	u32 hwords;
 	u32 hwords;
 	struct ipath_ib_header hdr;
 	struct ipath_ib_header hdr;
 	struct ipath_other_headers *ohdr;
 	struct ipath_other_headers *ohdr;
+	unsigned long flags;
 
 
 	/* Don't send ACK or NAK if a RDMA read or atomic is pending. */
 	/* 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)
+	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;
 		goto queue_ack;
 
 
 	/* Construct the header. */
 	/* Construct the header. */
@@ -640,11 +638,11 @@ static void send_rc_ack(struct ipath_qp *qp)
 	dev->n_rc_qacks++;
 	dev->n_rc_qacks++;
 
 
 queue_ack:
 queue_ack:
-	spin_lock_irq(&qp->s_lock);
+	spin_lock_irqsave(&qp->s_lock, flags);
 	qp->s_flags |= IPATH_S_ACK_PENDING;
 	qp->s_flags |= IPATH_S_ACK_PENDING;
 	qp->s_nak_state = qp->r_nak_state;
 	qp->s_nak_state = qp->r_nak_state;
 	qp->s_ack_psn = qp->r_ack_psn;
 	qp->s_ack_psn = qp->r_ack_psn;
-	spin_unlock_irq(&qp->s_lock);
+	spin_unlock_irqrestore(&qp->s_lock, flags);
 
 
 	/* Call ipath_do_rc_send() in another thread. */
 	/* Call ipath_do_rc_send() in another thread. */
 	tasklet_hi_schedule(&qp->s_task);
 	tasklet_hi_schedule(&qp->s_task);
@@ -1261,6 +1259,7 @@ ack_err:
 	wc.dlid_path_bits = 0;
 	wc.dlid_path_bits = 0;
 	wc.port_num = 0;
 	wc.port_num = 0;
 	ipath_sqerror_qp(qp, &wc);
 	ipath_sqerror_qp(qp, &wc);
+	spin_unlock_irqrestore(&qp->s_lock, flags);
 bail:
 bail:
 	return;
 	return;
 }
 }
@@ -1294,6 +1293,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
 	struct ipath_ack_entry *e;
 	struct ipath_ack_entry *e;
 	u8 i, prev;
 	u8 i, prev;
 	int old_req;
 	int old_req;
+	unsigned long flags;
 
 
 	if (diff > 0) {
 	if (diff > 0) {
 		/*
 		/*
@@ -1327,7 +1327,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
 	psn &= IPATH_PSN_MASK;
 	psn &= IPATH_PSN_MASK;
 	e = NULL;
 	e = NULL;
 	old_req = 1;
 	old_req = 1;
-	spin_lock_irq(&qp->s_lock);
+	spin_lock_irqsave(&qp->s_lock, flags);
 	for (i = qp->r_head_ack_queue; ; i = prev) {
 	for (i = qp->r_head_ack_queue; ; i = prev) {
 		if (i == qp->s_tail_ack_queue)
 		if (i == qp->s_tail_ack_queue)
 			old_req = 0;
 			old_req = 0;
@@ -1425,7 +1425,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
 		 * after all the previous RDMA reads and atomics.
 		 * after all the previous RDMA reads and atomics.
 		 */
 		 */
 		if (i == qp->r_head_ack_queue) {
 		if (i == qp->r_head_ack_queue) {
-			spin_unlock_irq(&qp->s_lock);
+			spin_unlock_irqrestore(&qp->s_lock, flags);
 			qp->r_nak_state = 0;
 			qp->r_nak_state = 0;
 			qp->r_ack_psn = qp->r_psn - 1;
 			qp->r_ack_psn = qp->r_psn - 1;
 			goto send_ack;
 			goto send_ack;
@@ -1439,11 +1439,10 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
 		break;
 		break;
 	}
 	}
 	qp->r_nak_state = 0;
 	qp->r_nak_state = 0;
-	spin_unlock_irq(&qp->s_lock);
 	tasklet_hi_schedule(&qp->s_task);
 	tasklet_hi_schedule(&qp->s_task);
 
 
 unlock_done:
 unlock_done:
-	spin_unlock_irq(&qp->s_lock);
+	spin_unlock_irqrestore(&qp->s_lock, flags);
 done:
 done:
 	return 1;
 	return 1;
 
 
@@ -1453,10 +1452,12 @@ send_ack:
 
 
 static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
 static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
 {
 {
-	spin_lock_irq(&qp->s_lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&qp->s_lock, flags);
 	qp->state = IB_QPS_ERR;
 	qp->state = IB_QPS_ERR;
 	ipath_error_qp(qp, err);
 	ipath_error_qp(qp, err);
-	spin_unlock_irq(&qp->s_lock);
+	spin_unlock_irqrestore(&qp->s_lock, flags);
 }
 }
 
 
 /**
 /**

+ 26 - 29
drivers/infiniband/hw/ipath/ipath_srq.c

@@ -139,33 +139,24 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
 	 * See ipath_mmap() for details.
 	 * See ipath_mmap() for details.
 	 */
 	 */
 	if (udata && udata->outlen >= sizeof(__u64)) {
 	if (udata && udata->outlen >= sizeof(__u64)) {
-		struct ipath_mmap_info *ip;
-		__u64 offset = (__u64) srq->rq.wq;
 		int err;
 		int err;
+		u32 s = sizeof(struct ipath_rwq) + srq->rq.size * sz;
 
 
-		err = ib_copy_to_udata(udata, &offset, sizeof(offset));
-		if (err) {
-			ret = ERR_PTR(err);
+		srq->ip =
+		    ipath_create_mmap_info(dev, s,
+					   ibpd->uobject->context,
+					   srq->rq.wq);
+		if (!srq->ip) {
+			ret = ERR_PTR(-ENOMEM);
 			goto bail_wq;
 			goto bail_wq;
 		}
 		}
 
 
-		/* Allocate info for ipath_mmap(). */
-		ip = kmalloc(sizeof(*ip), GFP_KERNEL);
-		if (!ip) {
-			ret = ERR_PTR(-ENOMEM);
-			goto bail_wq;
+		err = ib_copy_to_udata(udata, &srq->ip->offset,
+				       sizeof(srq->ip->offset));
+		if (err) {
+			ret = ERR_PTR(err);
+			goto bail_ip;
 		}
 		}
-		srq->ip = ip;
-		ip->context = ibpd->uobject->context;
-		ip->obj = srq->rq.wq;
-		kref_init(&ip->ref);
-		ip->mmap_cnt = 0;
-		ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
-				      srq->rq.size * sz);
-		spin_lock_irq(&dev->pending_lock);
-		ip->next = dev->pending_mmaps;
-		dev->pending_mmaps = ip;
-		spin_unlock_irq(&dev->pending_lock);
 	} else
 	} else
 		srq->ip = NULL;
 		srq->ip = NULL;
 
 
@@ -181,21 +172,27 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
 	if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
 	if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
 		spin_unlock(&dev->n_srqs_lock);
 		spin_unlock(&dev->n_srqs_lock);
 		ret = ERR_PTR(-ENOMEM);
 		ret = ERR_PTR(-ENOMEM);
-		goto bail_wq;
+		goto bail_ip;
 	}
 	}
 
 
  	dev->n_srqs_allocated++;
  	dev->n_srqs_allocated++;
 	spin_unlock(&dev->n_srqs_lock);
 	spin_unlock(&dev->n_srqs_lock);
 
 
+	if (srq->ip) {
+		spin_lock_irq(&dev->pending_lock);
+		list_add(&srq->ip->pending_mmaps, &dev->pending_mmaps);
+		spin_unlock_irq(&dev->pending_lock);
+	}
+
 	ret = &srq->ibsrq;
 	ret = &srq->ibsrq;
 	goto done;
 	goto done;
 
 
+bail_ip:
+	kfree(srq->ip);
 bail_wq:
 bail_wq:
 	vfree(srq->rq.wq);
 	vfree(srq->rq.wq);
-
 bail_srq:
 bail_srq:
 	kfree(srq);
 	kfree(srq);
-
 done:
 done:
 	return ret;
 	return ret;
 }
 }
@@ -312,13 +309,13 @@ int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
 		if (srq->ip) {
 		if (srq->ip) {
 			struct ipath_mmap_info *ip = srq->ip;
 			struct ipath_mmap_info *ip = srq->ip;
 			struct ipath_ibdev *dev = to_idev(srq->ibsrq.device);
 			struct ipath_ibdev *dev = to_idev(srq->ibsrq.device);
+			u32 s = sizeof(struct ipath_rwq) + size * sz;
 
 
-			ip->obj = wq;
-			ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
-					      size * sz);
+			ipath_update_mmap_info(dev, ip, s, wq);
 			spin_lock_irq(&dev->pending_lock);
 			spin_lock_irq(&dev->pending_lock);
-			ip->next = dev->pending_mmaps;
-			dev->pending_mmaps = ip;
+			if (list_empty(&ip->pending_mmaps))
+				list_add(&ip->pending_mmaps,
+					 &dev->pending_mmaps);
 			spin_unlock_irq(&dev->pending_lock);
 			spin_unlock_irq(&dev->pending_lock);
 		}
 		}
 	} else if (attr_mask & IB_SRQ_LIMIT) {
 	} else if (attr_mask & IB_SRQ_LIMIT) {

+ 4 - 0
drivers/infiniband/hw/ipath/ipath_verbs.c

@@ -1476,7 +1476,10 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err_lk;
 		goto err_lk;
 	}
 	}
+	INIT_LIST_HEAD(&idev->pending_mmaps);
 	spin_lock_init(&idev->pending_lock);
 	spin_lock_init(&idev->pending_lock);
+	idev->mmap_offset = PAGE_SIZE;
+	spin_lock_init(&idev->mmap_offset_lock);
 	INIT_LIST_HEAD(&idev->pending[0]);
 	INIT_LIST_HEAD(&idev->pending[0]);
 	INIT_LIST_HEAD(&idev->pending[1]);
 	INIT_LIST_HEAD(&idev->pending[1]);
 	INIT_LIST_HEAD(&idev->pending[2]);
 	INIT_LIST_HEAD(&idev->pending[2]);
@@ -1558,6 +1561,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
 		(1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
 		(1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
 	dev->node_type = RDMA_NODE_IB_CA;
 	dev->node_type = RDMA_NODE_IB_CA;
 	dev->phys_port_cnt = 1;
 	dev->phys_port_cnt = 1;
+	dev->num_comp_vectors = 1;
 	dev->dma_device = &dd->pcidev->dev;
 	dev->dma_device = &dd->pcidev->dev;
 	dev->query_device = ipath_query_device;
 	dev->query_device = ipath_query_device;
 	dev->modify_device = ipath_modify_device;
 	dev->modify_device = ipath_modify_device;

+ 17 - 7
drivers/infiniband/hw/ipath/ipath_verbs.h

@@ -173,12 +173,12 @@ struct ipath_ah {
  * this as its vm_private_data.
  * this as its vm_private_data.
  */
  */
 struct ipath_mmap_info {
 struct ipath_mmap_info {
-	struct ipath_mmap_info *next;
+	struct list_head pending_mmaps;
 	struct ib_ucontext *context;
 	struct ib_ucontext *context;
 	void *obj;
 	void *obj;
+	__u64 offset;
 	struct kref ref;
 	struct kref ref;
 	unsigned size;
 	unsigned size;
-	unsigned mmap_cnt;
 };
 };
 
 
 /*
 /*
@@ -422,7 +422,7 @@ struct ipath_qp {
 #define IPATH_S_RDMAR_PENDING	0x04
 #define IPATH_S_RDMAR_PENDING	0x04
 #define IPATH_S_ACK_PENDING	0x08
 #define IPATH_S_ACK_PENDING	0x08
 
 
-#define IPATH_PSN_CREDIT	2048
+#define IPATH_PSN_CREDIT	512
 
 
 /*
 /*
  * Since struct ipath_swqe is not a fixed size, we can't simply index into
  * Since struct ipath_swqe is not a fixed size, we can't simply index into
@@ -485,9 +485,10 @@ struct ipath_opcode_stats {
 
 
 struct ipath_ibdev {
 struct ipath_ibdev {
 	struct ib_device ibdev;
 	struct ib_device ibdev;
-	struct list_head dev_list;
 	struct ipath_devdata *dd;
 	struct ipath_devdata *dd;
-	struct ipath_mmap_info *pending_mmaps;
+	struct list_head pending_mmaps;
+	spinlock_t mmap_offset_lock;
+	u32 mmap_offset;
 	int ib_unit;		/* This is the device number */
 	int ib_unit;		/* This is the device number */
 	u16 sm_lid;		/* in host order */
 	u16 sm_lid;		/* in host order */
 	u8 sm_sl;
 	u8 sm_sl;
@@ -734,13 +735,13 @@ int ipath_destroy_srq(struct ib_srq *ibsrq);
 
 
 int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
 int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
 
 
-struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
+struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
 			      struct ib_ucontext *context,
 			      struct ib_ucontext *context,
 			      struct ib_udata *udata);
 			      struct ib_udata *udata);
 
 
 int ipath_destroy_cq(struct ib_cq *ibcq);
 int ipath_destroy_cq(struct ib_cq *ibcq);
 
 
-int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify);
+int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags);
 
 
 int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata);
 int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata);
 
 
@@ -768,6 +769,15 @@ int ipath_dealloc_fmr(struct ib_fmr *ibfmr);
 
 
 void ipath_release_mmap_info(struct kref *ref);
 void ipath_release_mmap_info(struct kref *ref);
 
 
+struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
+					       u32 size,
+					       struct ib_ucontext *context,
+					       void *obj);
+
+void ipath_update_mmap_info(struct ipath_ibdev *dev,
+			    struct ipath_mmap_info *ip,
+			    u32 size, void *obj);
+
 int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
 int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
 
 
 void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);
 void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);

+ 7 - 5
drivers/infiniband/hw/mthca/mthca_cq.c

@@ -726,11 +726,12 @@ repoll:
 	return err == 0 || err == -EAGAIN ? npolled : err;
 	return err == 0 || err == -EAGAIN ? npolled : err;
 }
 }
 
 
-int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify)
+int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags)
 {
 {
 	__be32 doorbell[2];
 	__be32 doorbell[2];
 
 
-	doorbell[0] = cpu_to_be32((notify == IB_CQ_SOLICITED ?
+	doorbell[0] = cpu_to_be32(((flags & IB_CQ_SOLICITED_MASK) ==
+				   IB_CQ_SOLICITED ?
 				   MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
 				   MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
 				   MTHCA_TAVOR_CQ_DB_REQ_NOT)      |
 				   MTHCA_TAVOR_CQ_DB_REQ_NOT)      |
 				  to_mcq(cq)->cqn);
 				  to_mcq(cq)->cqn);
@@ -743,7 +744,7 @@ int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify)
 	return 0;
 	return 0;
 }
 }
 
 
-int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
 {
 {
 	struct mthca_cq *cq = to_mcq(ibcq);
 	struct mthca_cq *cq = to_mcq(ibcq);
 	__be32 doorbell[2];
 	__be32 doorbell[2];
@@ -755,7 +756,8 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
 
 
 	doorbell[0] = ci;
 	doorbell[0] = ci;
 	doorbell[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
 	doorbell[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
-				  (notify == IB_CQ_SOLICITED ? 1 : 2));
+				  ((flags & IB_CQ_SOLICITED_MASK) ==
+				   IB_CQ_SOLICITED ? 1 : 2));
 
 
 	mthca_write_db_rec(doorbell, cq->arm_db);
 	mthca_write_db_rec(doorbell, cq->arm_db);
 
 
@@ -766,7 +768,7 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
 	wmb();
 	wmb();
 
 
 	doorbell[0] = cpu_to_be32((sn << 28)                       |
 	doorbell[0] = cpu_to_be32((sn << 28)                       |
-				  (notify == IB_CQ_SOLICITED ?
+				  ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
 				   MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
 				   MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
 				   MTHCA_ARBEL_CQ_DB_REQ_NOT)      |
 				   MTHCA_ARBEL_CQ_DB_REQ_NOT)      |
 				  cq->cqn);
 				  cq->cqn);

+ 2 - 2
drivers/infiniband/hw/mthca/mthca_dev.h

@@ -495,8 +495,8 @@ void mthca_unmap_eq_icm(struct mthca_dev *dev);
 
 
 int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
 int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
 		  struct ib_wc *entry);
 		  struct ib_wc *entry);
-int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
-int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
+int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
+int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
 int mthca_init_cq(struct mthca_dev *dev, int nent,
 int mthca_init_cq(struct mthca_dev *dev, int nent,
 		  struct mthca_ucontext *ctx, u32 pdn,
 		  struct mthca_ucontext *ctx, u32 pdn,
 		  struct mthca_cq *cq);
 		  struct mthca_cq *cq);

+ 2 - 0
drivers/infiniband/hw/mthca/mthca_provider.c

@@ -663,6 +663,7 @@ static int mthca_destroy_qp(struct ib_qp *qp)
 }
 }
 
 
 static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
 static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
+				     int comp_vector,
 				     struct ib_ucontext *context,
 				     struct ib_ucontext *context,
 				     struct ib_udata *udata)
 				     struct ib_udata *udata)
 {
 {
@@ -1292,6 +1293,7 @@ int mthca_register_device(struct mthca_dev *dev)
 		(1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
 		(1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
 	dev->ib_dev.node_type            = RDMA_NODE_IB_CA;
 	dev->ib_dev.node_type            = RDMA_NODE_IB_CA;
 	dev->ib_dev.phys_port_cnt        = dev->limits.num_ports;
 	dev->ib_dev.phys_port_cnt        = dev->limits.num_ports;
+	dev->ib_dev.num_comp_vectors     = 1;
 	dev->ib_dev.dma_device           = &dev->pdev->dev;
 	dev->ib_dev.dma_device           = &dev->pdev->dev;
 	dev->ib_dev.query_device         = mthca_query_device;
 	dev->ib_dev.query_device         = mthca_query_device;
 	dev->ib_dev.query_port           = mthca_query_port;
 	dev->ib_dev.query_port           = mthca_query_port;

+ 13 - 0
drivers/infiniband/hw/mthca/mthca_qp.c

@@ -701,6 +701,19 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH);
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH);
 	}
 	}
 
 
+	if (ibqp->qp_type == IB_QPT_RC &&
+	    cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
+		u8 sched_queue = ibqp->uobject ? 0x2 : 0x1;
+
+		if (mthca_is_memfree(dev))
+			qp_context->rlkey_arbel_sched_queue |= sched_queue;
+		else
+			qp_context->tavor_sched_queue |= cpu_to_be32(sched_queue);
+
+		qp_param->opt_param_mask |=
+			cpu_to_be32(MTHCA_QP_OPTPAR_SCHED_QUEUE);
+	}
+
 	if (attr_mask & IB_QP_TIMEOUT) {
 	if (attr_mask & IB_QP_TIMEOUT) {
 		qp_context->pri_path.ackto = attr->timeout << 3;
 		qp_context->pri_path.ackto = attr->timeout << 3;
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT);
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT);

+ 1 - 0
drivers/infiniband/ulp/ipoib/ipoib.h

@@ -310,6 +310,7 @@ extern struct workqueue_struct *ipoib_workqueue;
 
 
 /* functions */
 /* functions */
 
 
+int ipoib_poll(struct net_device *dev, int *budget);
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
 
 
 struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
 struct ipoib_ah *ipoib_create_ah(struct net_device *dev,

+ 9 - 5
drivers/infiniband/ulp/ipoib/ipoib_cm.c

@@ -370,7 +370,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 
 
 	if (!likely(wr_id & IPOIB_CM_RX_UPDATE_MASK)) {
 	if (!likely(wr_id & IPOIB_CM_RX_UPDATE_MASK)) {
 		p = wc->qp->qp_context;
 		p = wc->qp->qp_context;
-		if (time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
+		if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
 			spin_lock_irqsave(&priv->lock, flags);
 			spin_lock_irqsave(&priv->lock, flags);
 			p->jiffies = jiffies;
 			p->jiffies = jiffies;
 			/* Move this entry to list head, but do
 			/* Move this entry to list head, but do
@@ -416,7 +416,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 	skb->dev = dev;
 	skb->dev = dev;
 	/* XXX get correct PACKET_ type here */
 	/* XXX get correct PACKET_ type here */
 	skb->pkt_type = PACKET_HOST;
 	skb->pkt_type = PACKET_HOST;
-	netif_rx_ni(skb);
+	netif_receive_skb(skb);
 
 
 repost:
 repost:
 	if (unlikely(ipoib_cm_post_receive(dev, wr_id)))
 	if (unlikely(ipoib_cm_post_receive(dev, wr_id)))
@@ -592,7 +592,9 @@ int ipoib_cm_dev_open(struct net_device *dev)
 	priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, dev);
 	priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, dev);
 	if (IS_ERR(priv->cm.id)) {
 	if (IS_ERR(priv->cm.id)) {
 		printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name);
 		printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name);
-		return IS_ERR(priv->cm.id);
+		ret = PTR_ERR(priv->cm.id);
+		priv->cm.id = NULL;
+		return ret;
 	}
 	}
 
 
 	ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num),
 	ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num),
@@ -601,6 +603,7 @@ int ipoib_cm_dev_open(struct net_device *dev)
 		printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name,
 		printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name,
 		       IPOIB_CM_IETF_ID | priv->qp->qp_num);
 		       IPOIB_CM_IETF_ID | priv->qp->qp_num);
 		ib_destroy_cm_id(priv->cm.id);
 		ib_destroy_cm_id(priv->cm.id);
+		priv->cm.id = NULL;
 		return ret;
 		return ret;
 	}
 	}
 	return 0;
 	return 0;
@@ -611,10 +614,11 @@ void ipoib_cm_dev_stop(struct net_device *dev)
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_cm_rx *p;
 	struct ipoib_cm_rx *p;
 
 
-	if (!IPOIB_CM_SUPPORTED(dev->dev_addr))
+	if (!IPOIB_CM_SUPPORTED(dev->dev_addr) || !priv->cm.id)
 		return;
 		return;
 
 
 	ib_destroy_cm_id(priv->cm.id);
 	ib_destroy_cm_id(priv->cm.id);
+	priv->cm.id = NULL;
 	spin_lock_irq(&priv->lock);
 	spin_lock_irq(&priv->lock);
 	while (!list_empty(&priv->cm.passive_ids)) {
 	while (!list_empty(&priv->cm.passive_ids)) {
 		p = list_entry(priv->cm.passive_ids.next, typeof(*p), list);
 		p = list_entry(priv->cm.passive_ids.next, typeof(*p), list);
@@ -789,7 +793,7 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
 	}
 	}
 
 
 	p->cq = ib_create_cq(priv->ca, ipoib_cm_tx_completion, NULL, p,
 	p->cq = ib_create_cq(priv->ca, ipoib_cm_tx_completion, NULL, p,
-			     ipoib_sendq_size + 1);
+			     ipoib_sendq_size + 1, 0);
 	if (IS_ERR(p->cq)) {
 	if (IS_ERR(p->cq)) {
 		ret = PTR_ERR(p->cq);
 		ret = PTR_ERR(p->cq);
 		ipoib_warn(priv, "failed to allocate tx cq: %d\n", ret);
 		ipoib_warn(priv, "failed to allocate tx cq: %d\n", ret);

+ 70 - 19
drivers/infiniband/ulp/ipoib/ipoib_ib.c

@@ -226,7 +226,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 		skb->dev = dev;
 		skb->dev = dev;
 		/* XXX get correct PACKET_ type here */
 		/* XXX get correct PACKET_ type here */
 		skb->pkt_type = PACKET_HOST;
 		skb->pkt_type = PACKET_HOST;
-		netif_rx_ni(skb);
+		netif_receive_skb(skb);
 	} else {
 	} else {
 		ipoib_dbg_data(priv, "dropping loopback packet\n");
 		ipoib_dbg_data(priv, "dropping loopback packet\n");
 		dev_kfree_skb_any(skb);
 		dev_kfree_skb_any(skb);
@@ -280,28 +280,63 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
 			   wc->status, wr_id, wc->vendor_err);
 			   wc->status, wr_id, wc->vendor_err);
 }
 }
 
 
-static void ipoib_ib_handle_wc(struct net_device *dev, struct ib_wc *wc)
+int ipoib_poll(struct net_device *dev, int *budget)
 {
 {
-	if (wc->wr_id & IPOIB_CM_OP_SRQ)
-		ipoib_cm_handle_rx_wc(dev, wc);
-	else if (wc->wr_id & IPOIB_OP_RECV)
-		ipoib_ib_handle_rx_wc(dev, wc);
-	else
-		ipoib_ib_handle_tx_wc(dev, wc);
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	int max = min(*budget, dev->quota);
+	int done;
+	int t;
+	int empty;
+	int n, i;
+
+	done  = 0;
+	empty = 0;
+
+	while (max) {
+		t = min(IPOIB_NUM_WC, max);
+		n = ib_poll_cq(priv->cq, t, priv->ibwc);
+
+		for (i = 0; i < n; ++i) {
+			struct ib_wc *wc = priv->ibwc + i;
+
+			if (wc->wr_id & IPOIB_CM_OP_SRQ) {
+				++done;
+				--max;
+				ipoib_cm_handle_rx_wc(dev, wc);
+			} else if (wc->wr_id & IPOIB_OP_RECV) {
+				++done;
+				--max;
+				ipoib_ib_handle_rx_wc(dev, wc);
+			} else
+				ipoib_ib_handle_tx_wc(dev, wc);
+		}
+
+		if (n != t) {
+			empty = 1;
+			break;
+		}
+	}
+
+	dev->quota -= done;
+	*budget    -= done;
+
+	if (empty) {
+		netif_rx_complete(dev);
+		if (unlikely(ib_req_notify_cq(priv->cq,
+					      IB_CQ_NEXT_COMP |
+					      IB_CQ_REPORT_MISSED_EVENTS)) &&
+		    netif_rx_reschedule(dev, 0))
+			return 1;
+
+		return 0;
+	}
+
+	return 1;
 }
 }
 
 
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
 {
 {
-	struct net_device *dev = (struct net_device *) dev_ptr;
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	int n, i;
-
-	ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
-	do {
-		n = ib_poll_cq(cq, IPOIB_NUM_WC, priv->ibwc);
-		for (i = 0; i < n; ++i)
-			ipoib_ib_handle_wc(dev, priv->ibwc + i);
-	} while (n == IPOIB_NUM_WC);
+	netif_rx_schedule(dev_ptr);
 }
 }
 
 
 static inline int post_send(struct ipoib_dev_priv *priv,
 static inline int post_send(struct ipoib_dev_priv *priv,
@@ -514,9 +549,10 @@ int ipoib_ib_dev_stop(struct net_device *dev)
 	struct ib_qp_attr qp_attr;
 	struct ib_qp_attr qp_attr;
 	unsigned long begin;
 	unsigned long begin;
 	struct ipoib_tx_buf *tx_req;
 	struct ipoib_tx_buf *tx_req;
-	int i;
+	int i, n;
 
 
 	clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
 	clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
+	netif_poll_disable(dev);
 
 
 	ipoib_cm_dev_stop(dev);
 	ipoib_cm_dev_stop(dev);
 
 
@@ -568,6 +604,18 @@ int ipoib_ib_dev_stop(struct net_device *dev)
 			goto timeout;
 			goto timeout;
 		}
 		}
 
 
+		do {
+			n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc);
+			for (i = 0; i < n; ++i) {
+				if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ)
+					ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
+				else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV)
+					ipoib_ib_handle_rx_wc(dev, priv->ibwc + i);
+				else
+					ipoib_ib_handle_tx_wc(dev, priv->ibwc + i);
+			}
+		} while (n == IPOIB_NUM_WC);
+
 		msleep(1);
 		msleep(1);
 	}
 	}
 
 
@@ -596,6 +644,9 @@ timeout:
 		msleep(1);
 		msleep(1);
 	}
 	}
 
 
+	netif_poll_enable(dev);
+	ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP);
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 2 - 0
drivers/infiniband/ulp/ipoib/ipoib_main.c

@@ -948,6 +948,8 @@ static void ipoib_setup(struct net_device *dev)
 	dev->hard_header 	 = ipoib_hard_header;
 	dev->hard_header 	 = ipoib_hard_header;
 	dev->set_multicast_list  = ipoib_set_mcast_list;
 	dev->set_multicast_list  = ipoib_set_mcast_list;
 	dev->neigh_setup         = ipoib_neigh_setup_dev;
 	dev->neigh_setup         = ipoib_neigh_setup_dev;
+	dev->poll                = ipoib_poll;
+	dev->weight              = 100;
 
 
 	dev->watchdog_timeo 	 = HZ;
 	dev->watchdog_timeo 	 = HZ;
 
 

+ 1 - 1
drivers/infiniband/ulp/ipoib/ipoib_verbs.c

@@ -187,7 +187,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
 	if (!ret)
 	if (!ret)
 		size += ipoib_recvq_size;
 		size += ipoib_recvq_size;
 
 
-	priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size);
+	priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
 	if (IS_ERR(priv->cq)) {
 	if (IS_ERR(priv->cq)) {
 		printk(KERN_WARNING "%s: failed to create CQ\n", ca->name);
 		printk(KERN_WARNING "%s: failed to create CQ\n", ca->name);
 		goto out_free_mr;
 		goto out_free_mr;

+ 1 - 1
drivers/infiniband/ulp/iser/iser_verbs.c

@@ -76,7 +76,7 @@ static int iser_create_device_ib_res(struct iser_device *device)
 				  iser_cq_callback,
 				  iser_cq_callback,
 				  iser_cq_event_callback,
 				  iser_cq_event_callback,
 				  (void *)device,
 				  (void *)device,
-				  ISER_MAX_CQ_LEN);
+				  ISER_MAX_CQ_LEN, 0);
 	if (IS_ERR(device->cq))
 	if (IS_ERR(device->cq))
 		goto cq_err;
 		goto cq_err;
 
 

+ 25 - 2
drivers/infiniband/ulp/srp/ib_srp.c

@@ -197,7 +197,7 @@ static int srp_create_target_ib(struct srp_target_port *target)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	target->cq = ib_create_cq(target->srp_host->dev->dev, srp_completion,
 	target->cq = ib_create_cq(target->srp_host->dev->dev, srp_completion,
-				  NULL, target, SRP_CQ_SIZE);
+				  NULL, target, SRP_CQ_SIZE, 0);
 	if (IS_ERR(target->cq)) {
 	if (IS_ERR(target->cq)) {
 		ret = PTR_ERR(target->cq);
 		ret = PTR_ERR(target->cq);
 		goto out;
 		goto out;
@@ -1468,6 +1468,25 @@ static ssize_t show_dgid(struct class_device *cdev, char *buf)
 		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
 		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
 }
 }
 
 
+static ssize_t show_orig_dgid(struct class_device *cdev, char *buf)
+{
+	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+	if (target->state == SRP_TARGET_DEAD ||
+	    target->state == SRP_TARGET_REMOVED)
+		return -ENODEV;
+
+	return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+		       be16_to_cpu(target->orig_dgid[0]),
+		       be16_to_cpu(target->orig_dgid[1]),
+		       be16_to_cpu(target->orig_dgid[2]),
+		       be16_to_cpu(target->orig_dgid[3]),
+		       be16_to_cpu(target->orig_dgid[4]),
+		       be16_to_cpu(target->orig_dgid[5]),
+		       be16_to_cpu(target->orig_dgid[6]),
+		       be16_to_cpu(target->orig_dgid[7]));
+}
+
 static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf)
 static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf)
 {
 {
 	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
 	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
@@ -1498,6 +1517,7 @@ static CLASS_DEVICE_ATTR(ioc_guid,	  S_IRUGO, show_ioc_guid,	 NULL);
 static CLASS_DEVICE_ATTR(service_id,	  S_IRUGO, show_service_id,	 NULL);
 static CLASS_DEVICE_ATTR(service_id,	  S_IRUGO, show_service_id,	 NULL);
 static CLASS_DEVICE_ATTR(pkey,		  S_IRUGO, show_pkey,		 NULL);
 static CLASS_DEVICE_ATTR(pkey,		  S_IRUGO, show_pkey,		 NULL);
 static CLASS_DEVICE_ATTR(dgid,		  S_IRUGO, show_dgid,		 NULL);
 static CLASS_DEVICE_ATTR(dgid,		  S_IRUGO, show_dgid,		 NULL);
+static CLASS_DEVICE_ATTR(orig_dgid,	  S_IRUGO, show_orig_dgid,	 NULL);
 static CLASS_DEVICE_ATTR(zero_req_lim,	  S_IRUGO, show_zero_req_lim,	 NULL);
 static CLASS_DEVICE_ATTR(zero_req_lim,	  S_IRUGO, show_zero_req_lim,	 NULL);
 static CLASS_DEVICE_ATTR(local_ib_port,   S_IRUGO, show_local_ib_port,	 NULL);
 static CLASS_DEVICE_ATTR(local_ib_port,   S_IRUGO, show_local_ib_port,	 NULL);
 static CLASS_DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
 static CLASS_DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
@@ -1508,6 +1528,7 @@ static struct class_device_attribute *srp_host_attrs[] = {
 	&class_device_attr_service_id,
 	&class_device_attr_service_id,
 	&class_device_attr_pkey,
 	&class_device_attr_pkey,
 	&class_device_attr_dgid,
 	&class_device_attr_dgid,
+	&class_device_attr_orig_dgid,
 	&class_device_attr_zero_req_lim,
 	&class_device_attr_zero_req_lim,
 	&class_device_attr_local_ib_port,
 	&class_device_attr_local_ib_port,
 	&class_device_attr_local_ib_device,
 	&class_device_attr_local_ib_device,
@@ -1516,7 +1537,8 @@ static struct class_device_attribute *srp_host_attrs[] = {
 
 
 static struct scsi_host_template srp_template = {
 static struct scsi_host_template srp_template = {
 	.module				= THIS_MODULE,
 	.module				= THIS_MODULE,
-	.name				= DRV_NAME,
+	.name				= "InfiniBand SRP initiator",
+	.proc_name			= DRV_NAME,
 	.info				= srp_target_info,
 	.info				= srp_target_info,
 	.queuecommand			= srp_queuecommand,
 	.queuecommand			= srp_queuecommand,
 	.eh_abort_handler		= srp_abort,
 	.eh_abort_handler		= srp_abort,
@@ -1662,6 +1684,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
 				target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
 				target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
 			}
 			}
 			kfree(p);
 			kfree(p);
+			memcpy(target->orig_dgid, target->path.dgid.raw, 16);
 			break;
 			break;
 
 
 		case SRP_OPT_PKEY:
 		case SRP_OPT_PKEY:

+ 1 - 0
drivers/infiniband/ulp/srp/ib_srp.h

@@ -129,6 +129,7 @@ struct srp_target_port {
 	unsigned int		scsi_id;
 	unsigned int		scsi_id;
 
 
 	struct ib_sa_path_rec	path;
 	struct ib_sa_path_rec	path;
+	__be16			orig_dgid[8];
 	struct ib_sa_query     *path_query;
 	struct ib_sa_query     *path_query;
 	int			path_query_id;
 	int			path_query_id;
 
 

+ 2 - 2
drivers/net/cxgb3/version.h

@@ -38,7 +38,7 @@
 #define DRV_VERSION "1.0-ko"
 #define DRV_VERSION "1.0-ko"
 
 
 /* Firmware version */
 /* Firmware version */
-#define FW_VERSION_MAJOR 3
-#define FW_VERSION_MINOR 3
+#define FW_VERSION_MAJOR 4
+#define FW_VERSION_MINOR 0
 #define FW_VERSION_MICRO 0
 #define FW_VERSION_MICRO 0
 #endif				/* __CHELSIO_VERSION_H */
 #endif				/* __CHELSIO_VERSION_H */

+ 37 - 10
include/rdma/ib_verbs.h

@@ -431,9 +431,11 @@ struct ib_wc {
 	u8			port_num;	/* valid only for DR SMPs on switches */
 	u8			port_num;	/* valid only for DR SMPs on switches */
 };
 };
 
 
-enum ib_cq_notify {
-	IB_CQ_SOLICITED,
-	IB_CQ_NEXT_COMP
+enum ib_cq_notify_flags {
+	IB_CQ_SOLICITED			= 1 << 0,
+	IB_CQ_NEXT_COMP			= 1 << 1,
+	IB_CQ_SOLICITED_MASK		= IB_CQ_SOLICITED | IB_CQ_NEXT_COMP,
+	IB_CQ_REPORT_MISSED_EVENTS	= 1 << 2,
 };
 };
 
 
 enum ib_srq_attr_mask {
 enum ib_srq_attr_mask {
@@ -912,6 +914,8 @@ struct ib_device {
 
 
 	u32                           flags;
 	u32                           flags;
 
 
+	int			      num_comp_vectors;
+
 	struct iw_cm_verbs	     *iwcm;
 	struct iw_cm_verbs	     *iwcm;
 
 
 	int		           (*query_device)(struct ib_device *device,
 	int		           (*query_device)(struct ib_device *device,
@@ -978,6 +982,7 @@ struct ib_device {
 						struct ib_recv_wr *recv_wr,
 						struct ib_recv_wr *recv_wr,
 						struct ib_recv_wr **bad_recv_wr);
 						struct ib_recv_wr **bad_recv_wr);
 	struct ib_cq *             (*create_cq)(struct ib_device *device, int cqe,
 	struct ib_cq *             (*create_cq)(struct ib_device *device, int cqe,
+						int comp_vector,
 						struct ib_ucontext *context,
 						struct ib_ucontext *context,
 						struct ib_udata *udata);
 						struct ib_udata *udata);
 	int                        (*destroy_cq)(struct ib_cq *cq);
 	int                        (*destroy_cq)(struct ib_cq *cq);
@@ -987,7 +992,7 @@ struct ib_device {
 					      struct ib_wc *wc);
 					      struct ib_wc *wc);
 	int                        (*peek_cq)(struct ib_cq *cq, int wc_cnt);
 	int                        (*peek_cq)(struct ib_cq *cq, int wc_cnt);
 	int                        (*req_notify_cq)(struct ib_cq *cq,
 	int                        (*req_notify_cq)(struct ib_cq *cq,
-						    enum ib_cq_notify cq_notify);
+						    enum ib_cq_notify_flags flags);
 	int                        (*req_ncomp_notif)(struct ib_cq *cq,
 	int                        (*req_ncomp_notif)(struct ib_cq *cq,
 						      int wc_cnt);
 						      int wc_cnt);
 	struct ib_mr *             (*get_dma_mr)(struct ib_pd *pd,
 	struct ib_mr *             (*get_dma_mr)(struct ib_pd *pd,
@@ -1358,13 +1363,15 @@ static inline int ib_post_recv(struct ib_qp *qp,
  * @cq_context: Context associated with the CQ returned to the user via
  * @cq_context: Context associated with the CQ returned to the user via
  *   the associated completion and event handlers.
  *   the associated completion and event handlers.
  * @cqe: The minimum size of the CQ.
  * @cqe: The minimum size of the CQ.
+ * @comp_vector - Completion vector used to signal completion events.
+ *     Must be >= 0 and < context->num_comp_vectors.
  *
  *
  * Users can examine the cq structure to determine the actual CQ size.
  * Users can examine the cq structure to determine the actual CQ size.
  */
  */
 struct ib_cq *ib_create_cq(struct ib_device *device,
 struct ib_cq *ib_create_cq(struct ib_device *device,
 			   ib_comp_handler comp_handler,
 			   ib_comp_handler comp_handler,
 			   void (*event_handler)(struct ib_event *, void *),
 			   void (*event_handler)(struct ib_event *, void *),
-			   void *cq_context, int cqe);
+			   void *cq_context, int cqe, int comp_vector);
 
 
 /**
 /**
  * ib_resize_cq - Modifies the capacity of the CQ.
  * ib_resize_cq - Modifies the capacity of the CQ.
@@ -1414,14 +1421,34 @@ int ib_peek_cq(struct ib_cq *cq, int wc_cnt);
 /**
 /**
  * ib_req_notify_cq - Request completion notification on a CQ.
  * ib_req_notify_cq - Request completion notification on a CQ.
  * @cq: The CQ to generate an event for.
  * @cq: The CQ to generate an event for.
- * @cq_notify: If set to %IB_CQ_SOLICITED, completion notification will
- *   occur on the next solicited event. If set to %IB_CQ_NEXT_COMP,
- *   notification will occur on the next completion.
+ * @flags:
+ *   Must contain exactly one of %IB_CQ_SOLICITED or %IB_CQ_NEXT_COMP
+ *   to request an event on the next solicited event or next work
+ *   completion at any type, respectively. %IB_CQ_REPORT_MISSED_EVENTS
+ *   may also be |ed in to request a hint about missed events, as
+ *   described below.
+ *
+ * Return Value:
+ *    < 0 means an error occurred while requesting notification
+ *   == 0 means notification was requested successfully, and if
+ *        IB_CQ_REPORT_MISSED_EVENTS was passed in, then no events
+ *        were missed and it is safe to wait for another event.  In
+ *        this case is it guaranteed that any work completions added
+ *        to the CQ since the last CQ poll will trigger a completion
+ *        notification event.
+ *    > 0 is only returned if IB_CQ_REPORT_MISSED_EVENTS was passed
+ *        in.  It means that the consumer must poll the CQ again to
+ *        make sure it is empty to avoid missing an event because of a
+ *        race between requesting notification and an entry being
+ *        added to the CQ.  This return value means it is possible
+ *        (but not guaranteed) that a work completion has been added
+ *        to the CQ since the last poll without triggering a
+ *        completion notification event.
  */
  */
 static inline int ib_req_notify_cq(struct ib_cq *cq,
 static inline int ib_req_notify_cq(struct ib_cq *cq,
-				   enum ib_cq_notify cq_notify)
+				   enum ib_cq_notify_flags flags)
 {
 {
-	return cq->device->req_notify_cq(cq, cq_notify);
+	return cq->device->req_notify_cq(cq, flags);
 }
 }
 
 
 /**
 /**