Skip to contentSkip to conversation

RDMA/cxgb4: Support on-chip SQs.

PATCH In review Steve Wise 2 participants 5 messages Sep 13, 2010 – Sep 29, 2010 4 messages not in the archive

Subsystems (2)
lore
Share & tools
lore

Steve Wise

author
#0 lore raw

PATCH v2 9/11 RDMA/cxgb4: Support on-chip SQs.

T4 support on-chip SQs to reduce latency. This patch adds support for this in iw_cxgb4.

Changes:

Manage ocqp memory like other adapter mem resources.

Allocate user mode SQs from ocqp mem if available.

Map ocqp mem to user process using write combining.

Map PCIE_MA_SYNC reg to user process.

Bump uverbs ABI.

---

 drivers/infiniband/hw/cxgb4/device.c   |   19 ++++++
 drivers/infiniband/hw/cxgb4/iw_cxgb4.h |    7 ++
 drivers/infiniband/hw/cxgb4/provider.c |   28 ++++++---
 drivers/infiniband/hw/cxgb4/qp.c       |   98 +++++++++++++++++++++++++++-----
 drivers/infiniband/hw/cxgb4/resource.c |   56 ++++++++++++++++++
 drivers/infiniband/hw/cxgb4/t4.h       |   40 +++++++++++--
 drivers/infiniband/hw/cxgb4/user.h     |    7 ++
 7 files changed, 226 insertions(+), 29 deletions(-)
drivers/infiniband/hw/cxgb4/device.c +19 -0
index 2851bf8..986cfd7 100644
@@ -364,7 +364,14 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
 		printk(KERN_ERR MOD "error %d initializing rqt pool\n", err);
 		goto err3;
 	}
+	err = c4iw_ocqp_pool_create(rdev);
+	if (err) {
+		printk(KERN_ERR MOD "error %d initializing ocqp pool\n", err);
+		goto err4;
+	}
 	return 0;
+err4:
+	c4iw_rqtpool_destroy(rdev);
 err3:
 	c4iw_pblpool_destroy(rdev);
 err2:
@@ -391,6 +398,7 @@ static void c4iw_remove(struct c4iw_dev *dev)
 	idr_destroy(&dev->cqidr);
 	idr_destroy(&dev->qpidr);
 	idr_destroy(&dev->mmidr);
+	iounmap(dev->rdev.oc_mw_kva);
 	ib_dealloc_device(&dev->ibdev);
 }
 
@@ -406,6 +414,17 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
 	}
 	devp->rdev.lldi = *infop;
 
+	devp->rdev.oc_mw_pa = pci_resource_start(devp->rdev.lldi.pdev, 2) +
+		(pci_resource_len(devp->rdev.lldi.pdev, 2) -
+		 roundup_pow_of_two(devp->rdev.lldi.vr->ocq.size));
+	devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa,
+					       devp->rdev.lldi.vr->ocq.size);
+
+	printk(KERN_INFO MOD "ocq memory: "
+	       "hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n",
+	       devp->rdev.lldi.vr->ocq.start, devp->rdev.lldi.vr->ocq.size,
+	       devp->rdev.oc_mw_pa, devp->rdev.oc_mw_kva);
+
 	mutex_lock(&dev_mutex);
 
 	ret = c4iw_rdev_open(&devp->rdev);
drivers/infiniband/hw/cxgb4/iw_cxgb4.h +7 -0
index 7780116..1c26922 100644
@@ -112,8 +112,11 @@ struct c4iw_rdev {
 	struct c4iw_dev_ucontext uctx;
 	struct gen_pool *pbl_pool;
 	struct gen_pool *rqt_pool;
+	struct gen_pool *ocqp_pool;
 	u32 flags;
 	struct cxgb4_lld_info lldi;
+	unsigned long oc_mw_pa;
+	void __iomem *oc_mw_kva;
 };
 
 static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
@@ -675,8 +678,10 @@ int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid);
 int c4iw_init_ctrl_qp(struct c4iw_rdev *rdev);
 int c4iw_pblpool_create(struct c4iw_rdev *rdev);
 int c4iw_rqtpool_create(struct c4iw_rdev *rdev);
+int c4iw_ocqp_pool_create(struct c4iw_rdev *rdev);
 void c4iw_pblpool_destroy(struct c4iw_rdev *rdev);
 void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev);
+void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev);
 void c4iw_destroy_resource(struct c4iw_resource *rscp);
 int c4iw_destroy_ctrl_qp(struct c4iw_rdev *rdev);
 int c4iw_register_device(struct c4iw_dev *dev);
@@ -742,6 +747,8 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size);
 void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
 u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size);
 void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
+u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size);
+void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size);
 int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb);
 void c4iw_flush_hw_cq(struct t4_cq *cq);
 void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count);
drivers/infiniband/hw/cxgb4/provider.c +19 -9
index 8f645c8..a49a9c1 100644
@@ -149,19 +149,28 @@ static int c4iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 	addr = mm->addr;
 	kfree(mm);
 
-	if ((addr >= pci_resource_start(rdev->lldi.pdev, 2)) &&
-	    (addr < (pci_resource_start(rdev->lldi.pdev, 2) +
-		       pci_resource_len(rdev->lldi.pdev, 2)))) {
+	if ((addr >= pci_resource_start(rdev->lldi.pdev, 0)) &&
+	    (addr < (pci_resource_start(rdev->lldi.pdev, 0) +
+		    pci_resource_len(rdev->lldi.pdev, 0)))) {
 
 		/*
-		 * Map T4 DB register.
+		 * MA_SYNC register...
 		 */
-		if (vma->vm_flags & VM_READ)
-			return -EPERM;
-
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-		vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
-		vma->vm_flags &= ~VM_MAYREAD;
+		ret = io_remap_pfn_range(vma, vma->vm_start,
+					 addr >> PAGE_SHIFT,
+					 len, vma->vm_page_prot);
+	} else if ((addr >= pci_resource_start(rdev->lldi.pdev, 2)) &&
+		   (addr < (pci_resource_start(rdev->lldi.pdev, 2) +
+		    pci_resource_len(rdev->lldi.pdev, 2)))) {
+
+		/*
+		 * Map user DB or OCQP memory...
+		 */
+		if (addr >= rdev->oc_mw_pa)
+			vma->vm_page_prot = t4_pgprot_wc(vma->vm_page_prot);
+		else
+			vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 		ret = io_remap_pfn_range(vma, vma->vm_start,
 					 addr >> PAGE_SHIFT,
 					 len, vma->vm_page_prot);
@@ -472,6 +481,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
 	dev->ibdev.post_send = c4iw_post_send;
 	dev->ibdev.post_recv = c4iw_post_receive;
 	dev->ibdev.get_protocol_stats = c4iw_get_mib;
+	dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION;
 
 	dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
 	if (!dev->ibdev.iwcm)
drivers/infiniband/hw/cxgb4/qp.c +83 -15

165 lines not on this page · raw message

drivers/infiniband/hw/cxgb4/resource.c +56 -0

59 lines not on this page · raw message

drivers/infiniband/hw/cxgb4/t4.h +35 -5
index 24f3690..17ea5fc 100644
@@ -52,6 +52,7 @@
 #define T4_STAG_UNSET 0xffffffff
 #define T4_FW_MAJ 0
 #define T4_EQ_STATUS_ENTRIES (L1_CACHE_BYTES > 64 ? 2 : 1)
+#define A_PCIE_MA_SYNC 0x30b4
 
 struct t4_status_page {
 	__be32 rsvd1;	/* flit 0 - hw owns */
@@ -266,10 +267,36 @@ struct t4_swsqe {
 	u16			idx;
 };
 
+static inline pgprot_t t4_pgprot_wc(pgprot_t prot)
+{
+#if defined(__i386__) || defined(__x86_64__)
+	return pgprot_writecombine(prot);
+#elif defined(CONFIG_PPC64)
+	return __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE) &
+			~(pgprot_t)_PAGE_GUARDED);
+#else
+	return pgprot_noncached(prot);
+#endif
+}
+
+static inline int t4_ocqp_supported(void)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+enum {
+	T4_SQ_ONCHIP = (1<<0),
+};
+
 struct t4_sq {
 	union t4_wr *queue;
 	dma_addr_t dma_addr;
 	DEFINE_DMA_UNMAP_ADDR(mapping);
+	unsigned long phys_addr;
 	struct t4_swsqe *sw_sq;
 	struct t4_swsqe *oldest_read;
 	u64 udb;
@@ -280,6 +307,7 @@ struct t4_sq {
 	u16 cidx;
 	u16 pidx;
 	u16 wq_pidx;
+	u16 flags;
 };
 
 struct t4_swrqe {
@@ -350,6 +378,11 @@ static inline void t4_rq_consume(struct t4_wq *wq)
 		wq->rq.cidx = 0;
 }
 
+static inline int t4_sq_onchip(struct t4_sq *sq)
+{
+	return sq->flags & T4_SQ_ONCHIP;
+}
+
 static inline int t4_sq_empty(struct t4_wq *wq)
 {
 	return wq->sq.in_use == 0;
@@ -396,30 +429,27 @@ static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc)
 
 static inline int t4_wq_in_error(struct t4_wq *wq)
 {
-	return wq->sq.queue[wq->sq.size].status.qp_err;
+	return wq->rq.queue[wq->rq.size].status.qp_err;
 }
 
 static inline void t4_set_wq_in_error(struct t4_wq *wq)
 {
-	wq->sq.queue[wq->sq.size].status.qp_err = 1;
 	wq->rq.queue[wq->rq.size].status.qp_err = 1;
 }
 
 static inline void t4_disable_wq_db(struct t4_wq *wq)
 {
-	wq->sq.queue[wq->sq.size].status.db_off = 1;
 	wq->rq.queue[wq->rq.size].status.db_off = 1;
 }
 
 static inline void t4_enable_wq_db(struct t4_wq *wq)
 {
-	wq->sq.queue[wq->sq.size].status.db_off = 0;
 	wq->rq.queue[wq->rq.size].status.db_off = 0;
 }
 
 static inline int t4_wq_db_enabled(struct t4_wq *wq)
 {
-	return !wq->sq.queue[wq->sq.size].status.db_off;
+	return !wq->rq.queue[wq->rq.size].status.db_off;
 }
 
 struct t4_cq {
drivers/infiniband/hw/cxgb4/user.h +7 -0
index ed6414a..e6669d5 100644
@@ -50,7 +50,13 @@ struct c4iw_create_cq_resp {
 	__u32 qid_mask;
 };
 
+
+enum {
+	C4IW_QPF_ONCHIP = (1<<0)
+};
+
 struct c4iw_create_qp_resp {
+	__u64 ma_sync_key;
 	__u64 sq_key;
 	__u64 rq_key;
 	__u64 sq_db_gts_key;
@@ -62,5 +68,6 @@ struct c4iw_create_qp_resp {
 	__u32 sq_size;
 	__u32 rq_size;
 	__u32 qid_mask;
+	__u32 flags;
 };
 #endif

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20100913162357.20948.28267.stgit-T4OLL4TyM9aNDNWfRnPdfg@public.gmane.org

#2 lore raw

As I said, I applied this, but I wonder:

Quoted 10 lines
drivers/infiniband/hw/cxgb4/t4.h +10 -0
+static inline pgprot_t t4_pgprot_wc(pgprot_t prot)
+{
+#if defined(__i386__) || defined(__x86_64__)
+	return pgprot_writecombine(prot);
+#elif defined(CONFIG_PPC64)
+	return __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE) &
+			~(pgprot_t)_PAGE_GUARDED);
+#else
+	return pgprot_noncached(prot);
+#endif

drivers/infiniband/hw/cxgb4/t4.h struct t4_swsqe { · line 289

Quoted 10 lines
drivers/infiniband/hw/cxgb4/t4.h +10 -0
+}
+
+static inline int t4_ocqp_supported(void)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
+	return 1;
+#else
+	return 0;
+#endif
+}

Is there any way to avoid this ifdef-ery? It seems at least the powerpc case should be wrapped up in an arch/powerpc version of pgprot_writecombine. Also doing this by hand as here leaves out for example ia64, which seems to have a definition of pgrprot_writecombine.

However I don't know what (if anything) we should do for the ocqp_supported test ...

- R.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#4 lore raw
Quoted 23 lines · Roland Dreier

As I said, I applied this, but I wonder:

Quoted 12 lines

+static inline pgprot_t t4_pgprot_wc(pgprot_t prot) +{
+#if defined(__i386__) || defined(__x86_64__)
+ return pgprot_writecombine(prot);
+#elif defined(CONFIG_PPC64)
+ return __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE)&
+ ~(pgprot_t)_PAGE_GUARDED);
+#else
+ return pgprot_noncached(prot);
+#endif
+}
+

Quoted 8 lines

+static inline int t4_ocqp_supported(void)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
+ return 1;
+#else
+ return 0;
+#endif
+}

Quoted 6 lines

Is there any way to avoid this ifdef-ery? It seems at least the powerpc case should be wrapped up in an arch/powerpc version of pgprot_writecombine. Also doing this by hand as here leaves out for example ia64, which seems to have a definition of pgrprot_writecombine.

We would remove it I guess. I see that mlx4 assumes pgprot_writecombine() exists and works correctly across all platforms. See mlx4_ib_mmap().

Quoted 3 lines

However I don't know what (if anything) we should do for the ocqp_supported test ...

If all platforms support pgprot_writecombine() correctly, then we don't need ocqp_supported().

Steve.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#6 lore raw
Quoted 3 lines

We would remove it I guess. I see that mlx4 assumes
pgprot_writecombine() exists and works correctly across all platforms. See mlx4_ib_mmap().

It might be more accurate to say that mlx4 assumes pgprot_writecombine() is defined on all platforms. Any platform that hasn't defined it (or where the concept of write combining doesn't make sense) just falls back to defining it as pgprot_noncached().

Quoted 1 line

From a quick grep it seems that /arch/powerpc has no definition of

pgprot_writecombine() but your code seems to say that one could be given.

Quoted 2 lines

If all platforms support pgprot_writecombine() correctly, then we don't need ocqp_supported().

As I said, it's a bit tricky. All platforms get some definition of pgprot_writecombine(), but some platforms might define it as just giving a non-cached mapping, which might lead to dire performance (perhaps worse than just putting the SQ in host memory). I'm not sure what the best way to handle it is -- I suppose if you wanted to get fancy you could do a quick benchmark on startup (if such a thing is possible).

- R.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#8 lore raw
Quoted 4 lines · Roland Dreier
Quoted 3 lines

We would remove it I guess. I see that mlx4 assumes
pgprot_writecombine() exists and works correctly across all platforms. See mlx4_ib_mmap().

Quoted 10 lines

It might be more accurate to say that mlx4 assumes pgprot_writecombine() is defined on all platforms. Any platform that hasn't defined it (or where the concept of write combining doesn't make sense) just falls back to defining it as pgprot_noncached().

Quoted 1 line

From a quick grep it seems that /arch/powerpc has no definition of

pgprot_writecombine() but your code seems to say that one could be given.

This came from the ofed version of mlx4. I assume it works. :)

Quoted 11 lines
Quoted 2 lines

If all platforms support pgprot_writecombine() correctly, then we don't need ocqp_supported().

As I said, it's a bit tricky. All platforms get some definition of pgprot_writecombine(), but some platforms might define it as just giving a non-cached mapping, which might lead to dire performance (perhaps worse than just putting the SQ in host memory). I'm not sure what the best way to handle it is -- I suppose if you wanted to get fancy you could do a quick benchmark on startup (if such a thing is possible).

oof. I don't want to get that fancy. :)

Seems like what I need is an arch-specific function that indicates if write combining is supported or not. Or leave the code as-is.

Steve.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html