Here's a first cut at OFED 1.3/Linux 2.6.23 patches to
address the "CQ/DMA race" that's possible on Altix systems
when CQs are allocated in user space.

(A description of this bug appears here:
http://lists.openfabrics.org/pipermail/general/2006-December/030251.html)

I'll post the kernel patch to lkml, but I'd appreciate any
comments from this list before doing that.

Obviously this is just a subset of the necessary kernel
changes required, since every use of dma_map_sg() would
need to be modified. Comments?

 arch/ia64/sn/pci/pci_dma.c                   |   19 ++++++++++++++-----
 drivers/infiniband/core/umem.c               |    5 +++--
 drivers/infiniband/hw/mthca/mthca_provider.c |   11 ++++++++++-
 drivers/infiniband/hw/mthca/mthca_user.h     |    8 +++++++-
 drivers/infiniband/ulp/srp/ib_srp.c          |    2 +-
 include/asm-generic/dma-mapping.h            |    4 ++--
 include/asm-generic/pci-dma-compat.h         |    2 +-
 include/asm-ia64/machvec.h                   |    2 +-
 include/rdma/ib_umem.h                       |    2 +-
 include/rdma/ib_verbs.h                      |    5 +++--

-- 
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
index d79ddac..d942390 100644
--- a/arch/ia64/sn/pci/pci_dma.c
+++ b/arch/ia64/sn/pci/pci_dma.c
@@ -245,7 +245,7 @@ EXPORT_SYMBOL(sn_dma_unmap_sg);
  * Maps each entry of @sg for DMA.
  */
 int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-                 int direction)
+                 int direction, int coherent)
 {
        unsigned long phys_addr;
        struct scatterlist *saved_sg = sg;
@@ -259,12 +259,21 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist 
*sg, int nhwentries,
         * Setup a DMA address for each entry in the scatterlist.
         */
        for (i = 0; i < nhwentries; i++, sg++) {
+               dma_addr_t dma_addr;
                phys_addr = SG_ENT_PHYS_ADDRESS(sg);
-               sg->dma_address = provider->dma_map(pdev,
-                                                   phys_addr, sg->length,
-                                                   SN_DMA_ADDR_PHYS);
 
-               if (!sg->dma_address) {
+               if (coherent) {
+                       dma_addr= provider->dma_map_consistent(pdev,
+                                                              phys_addr,       
+                                                              sg->length,
+                                                              
SN_DMA_ADDR_PHYS);
+               } else {
+                       dma_addr = provider->dma_map(pdev,
+                                                    phys_addr, sg->length,
+                                                    SN_DMA_ADDR_PHYS);
+               }
+
+               if (!(sg->dma_address = dma_addr)) {
                        printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
 
                        /*
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index d40652a..e9f9f42 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -66,7 +66,7 @@ static void __ib_umem_release(struct ib_device *dev, struct 
ib_umem *umem, int d
  * @access: IB_ACCESS_xxx flags for memory being pinned
  */
 struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
-                           size_t size, int access)
+                           size_t size, int access, int coherent)
 {
        struct ib_umem *umem;
        struct page **page_list;
@@ -154,7 +154,8 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, 
unsigned long addr,
                        chunk->nmap = ib_dma_map_sg(context->device,
                                                    &chunk->page_list[0],
                                                    chunk->nents,
-                                                   DMA_BIDIRECTIONAL);
+                                                   DMA_BIDIRECTIONAL,
+                                                   coherent);
                        if (chunk->nmap <= 0) {
                                for (i = 0; i < chunk->nents; ++i)
                                        put_page(chunk->page_list[i].page);
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c 
b/drivers/infiniband/hw/mthca/mthca_provider.c
index 6bcde1c..c0cf5f1 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1017,6 +1017,8 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, 
u64 start, u64 length,
        struct mthca_dev *dev = to_mdev(pd->device);
        struct ib_umem_chunk *chunk;
        struct mthca_mr *mr;
+       struct mthca_reg_mr ucmd;
+       int coherent;
        u64 *pages;
        int shift, n, len;
        int i, j, k;
@@ -1027,7 +1029,14 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, 
u64 start, u64 length,
        if (!mr)
                return ERR_PTR(-ENOMEM);
 
-       mr->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+       if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
+               err = -EFAULT;
+               goto err;
+       }
+       coherent = (int) ucmd.mr_attrs & MTHCA_MR_COHERENT;
+
+       mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, 
+                              coherent);
        if (IS_ERR(mr->umem)) {
                err = PTR_ERR(mr->umem);
                goto err;
diff --git a/drivers/infiniband/hw/mthca/mthca_user.h 
b/drivers/infiniband/hw/mthca/mthca_user.h
index 02cc0a7..f46773e 100644
--- a/drivers/infiniband/hw/mthca/mthca_user.h
+++ b/drivers/infiniband/hw/mthca/mthca_user.h
@@ -41,7 +41,7 @@
  * Increment this value if any changes that break userspace ABI
  * compatibility are made.
  */
-#define MTHCA_UVERBS_ABI_VERSION       1
+#define MTHCA_UVERBS_ABI_VERSION       2
 
 /*
  * Make sure that all structs defined in this file remain laid out so
@@ -61,6 +61,12 @@ struct mthca_alloc_pd_resp {
        __u32 reserved;
 };
 
+struct mthca_reg_mr {
+       __u32 mr_attrs;
+#define MTHCA_MR_COHERENT 0x1
+       __u32 reserved;
+};
+
 struct mthca_create_cq {
        __u32 lkey;
        __u32 pdn;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c 
b/drivers/infiniband/ulp/srp/ib_srp.c
index 39bf057..b7a4301 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -699,7 +699,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct 
srp_target_port *target,
        dev = target->srp_host->dev;
        ibdev = dev->dev;
 
-       count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction);
+       count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction, 0);
 
        fmt = SRP_DATA_DESC_DIRECT;
        len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf);
diff --git a/include/asm-generic/dma-mapping.h 
b/include/asm-generic/dma-mapping.h
index 783ab99..34e8357 100644
--- a/include/asm-generic/dma-mapping.h
+++ b/include/asm-generic/dma-mapping.h
@@ -89,7 +89,7 @@ dma_unmap_page(struct device *dev, dma_addr_t dma_address, 
size_t size,
 
 static inline int
 dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-          enum dma_data_direction direction)
+          enum dma_data_direction direction, int coherent)
 {
        BUG_ON(dev->bus != &pci_bus_type);
 
@@ -213,7 +213,7 @@ dma_unmap_page(struct device *dev, dma_addr_t dma_address, 
size_t size,
 
 static inline int
 dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-          enum dma_data_direction direction)
+          enum dma_data_direction direction, int coherent)
 {
        BUG();
        return 0;
diff --git a/include/asm-generic/pci-dma-compat.h 
b/include/asm-generic/pci-dma-compat.h
index 25c10e9..3e85b8e 100644
--- a/include/asm-generic/pci-dma-compat.h
+++ b/include/asm-generic/pci-dma-compat.h
@@ -60,7 +60,7 @@ static inline int
 pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
           int nents, int direction)
 {
-       return dma_map_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nents, (enum 
dma_data_direction)direction);
+       return dma_map_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nents, (enum 
dma_data_direction)direction, 0);
 }
 
 static inline void
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index ca33eb1..34e9a58 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -46,7 +46,7 @@ typedef void *ia64_mv_dma_alloc_coherent (struct device *, 
size_t, dma_addr_t *,
 typedef void ia64_mv_dma_free_coherent (struct device *, size_t, void *, 
dma_addr_t);
 typedef dma_addr_t ia64_mv_dma_map_single (struct device *, void *, size_t, 
int);
 typedef void ia64_mv_dma_unmap_single (struct device *, dma_addr_t, size_t, 
int);
-typedef int ia64_mv_dma_map_sg (struct device *, struct scatterlist *, int, 
int);
+typedef int ia64_mv_dma_map_sg (struct device *, struct scatterlist *, int, 
int, int);
 typedef void ia64_mv_dma_unmap_sg (struct device *, struct scatterlist *, int, 
int);
 typedef void ia64_mv_dma_sync_single_for_cpu (struct device *, dma_addr_t, 
size_t, int);
 typedef void ia64_mv_dma_sync_sg_for_cpu (struct device *, struct scatterlist 
*, int, int);
diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h
index c533d6c..08aeb87 100644
--- a/include/rdma/ib_umem.h
+++ b/include/rdma/ib_umem.h
@@ -61,7 +61,7 @@ struct ib_umem_chunk {
 #ifdef CONFIG_INFINIBAND_USER_MEM
 
 struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
-                           size_t size, int access);
+                           size_t size, int access, int coherent);
 void ib_umem_release(struct ib_umem *umem);
 int ib_umem_page_count(struct ib_umem *umem);
 
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 0627a6a..d5d3180 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1555,11 +1555,12 @@ static inline void ib_dma_unmap_page(struct ib_device 
*dev,
  */
 static inline int ib_dma_map_sg(struct ib_device *dev,
                                struct scatterlist *sg, int nents,
-                               enum dma_data_direction direction)
+                               enum dma_data_direction direction, 
+                               int coherent)
 {
        if (dev->dma_ops)
                return dev->dma_ops->map_sg(dev, sg, nents, direction);
-       return dma_map_sg(dev->dma_device, sg, nents, direction);
+       return dma_map_sg(dev->dma_device, sg, nents, direction, coherent);
 }
 
 /**

-- 
Arthur

_______________________________________________
general mailing list
[email protected]
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to