RDMA/cxgb3: Don't add PBL memory to gen_pool in chunks
authorRoland Dreier <rolandd@cisco.com>
Tue, 6 May 2008 22:03:38 +0000 (15:03 -0700)
committerRoland Dreier <rolandd@cisco.com>
Tue, 6 May 2008 22:03:38 +0000 (15:03 -0700)
Current iw_cxgb3 code adds PBL memory to the driver's gen_pool in 2 MB
chunks.  This limits the largest single allocation that can be done to
the same size, which means that with 4 KB pages, each of which takes 8
bytes of PBL memory, the largest memory region that can be allocated
is 1 GB (256K PBL entries * 4 KB/entry).

Remove this limit by adding all the PBL memory in a single gen_pool
chunk, if possible.  Add code that falls back to smaller chunks if
gen_pool_add() fails, which can happen if there is not sufficient
contiguous lowmem for the internal gen_pool bitmap.

Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/cxgb3/cxio_resource.c

index 45ed4f25ef785b1efa23cd6f335d8569e4c81c55..bd233c087653de5fed49dfbbf95f4d53cb43b7d0 100644 (file)
@@ -250,7 +250,6 @@ void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
  */
 
 #define MIN_PBL_SHIFT 8                        /* 256B == min PBL size (32 entries) */
-#define PBL_CHUNK 2*1024*1024
 
 u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size)
 {
@@ -267,14 +266,35 @@ void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
 
 int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p)
 {
-       unsigned long i;
+       unsigned pbl_start, pbl_chunk;
+
        rdev_p->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1);
-       if (rdev_p->pbl_pool)
-               for (i = rdev_p->rnic_info.pbl_base;
-                    i <= rdev_p->rnic_info.pbl_top - PBL_CHUNK + 1;
-                    i += PBL_CHUNK)
-                       gen_pool_add(rdev_p->pbl_pool, i, PBL_CHUNK, -1);
-       return rdev_p->pbl_pool ? 0 : -ENOMEM;
+       if (!rdev_p->pbl_pool)
+               return -ENOMEM;
+
+       pbl_start = rdev_p->rnic_info.pbl_base;
+       pbl_chunk = rdev_p->rnic_info.pbl_top - pbl_start + 1;
+
+       while (pbl_start < rdev_p->rnic_info.pbl_top) {
+               pbl_chunk = min(rdev_p->rnic_info.pbl_top - pbl_start + 1,
+                               pbl_chunk);
+               if (gen_pool_add(rdev_p->pbl_pool, pbl_start, pbl_chunk, -1)) {
+                       PDBG("%s failed to add PBL chunk (%x/%x)\n",
+                            __func__, pbl_start, pbl_chunk);
+                       if (pbl_chunk <= 1024 << MIN_PBL_SHIFT) {
+                               printk(KERN_WARNING MOD "%s: Failed to add all PBL chunks (%x/%x)\n",
+                                      __func__, pbl_start, rdev_p->rnic_info.pbl_top - pbl_start);
+                               return 0;
+                       }
+                       pbl_chunk >>= 1;
+               } else {
+                       PDBG("%s added PBL chunk (%x/%x)\n",
+                            __func__, pbl_start, pbl_chunk);
+                       pbl_start += pbl_chunk;
+               }
+       }
+
+       return 0;
 }
 
 void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p)