mlx4_core: Allow large mlx4_buddy bitmaps
authorYishai Hadas <yishaih@mellanox.com>
Mon, 13 Aug 2012 08:15:06 +0000 (08:15 +0000)
committerRoland Dreier <roland@purestorage.com>
Thu, 16 Aug 2012 04:05:20 +0000 (21:05 -0700)
mlx4_buddy_init uses kmalloc() to allocate bitmaps, which fails when
the required size is beyond the max supported value (or when memory is
too fragmented to handle a huge allocation).  Extend this to use use
vmalloc() if kmalloc() fails, and take that into account when freeing
the bitmaps as well.

This fixes a driver load failure when log num mtt is 26 or higher, and
is a step in the direction of allowing to register huge amounts of
memory on large memory systems.

Signed-off-by: Yishai Hadas <yishaih@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/net/ethernet/mellanox/mlx4/mr.c

index af55b7c..d6a3a39 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/vmalloc.h>
 
 #include <linux/mlx4/cmd.h>
 
@@ -130,8 +131,11 @@ static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
        for (i = 0; i <= buddy->max_order; ++i) {
                s = BITS_TO_LONGS(1 << (buddy->max_order - i));
                buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL);
-               if (!buddy->bits[i])
-                       goto err_out_free;
+               if (!buddy->bits[i]) {
+                       buddy->bits[i] = vmalloc(s * sizeof(long));
+                       if (!buddy->bits[i])
+                               goto err_out_free;
+               }
                bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i));
        }
 
@@ -142,7 +146,10 @@ static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
 
 err_out_free:
        for (i = 0; i <= buddy->max_order; ++i)
-               kfree(buddy->bits[i]);
+               if (buddy->bits[i] && is_vmalloc_addr(buddy->bits[i]))
+                       vfree(buddy->bits[i]);
+               else
+                       kfree(buddy->bits[i]);
 
 err_out:
        kfree(buddy->bits);
@@ -156,7 +163,10 @@ static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy)
        int i;
 
        for (i = 0; i <= buddy->max_order; ++i)
-               kfree(buddy->bits[i]);
+               if (is_vmalloc_addr(buddy->bits[i]))
+                       vfree(buddy->bits[i]);
+               else
+                       kfree(buddy->bits[i]);
 
        kfree(buddy->bits);
        kfree(buddy->num_free);