From 213f61b44b54edbcbf272e694e889c61412be579 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 16 Jun 2016 11:13:41 +0300 Subject: [PATCH] IB/mlx4: Ensure cache line boundaries for dma_map_single "In order for memory mapped by this API to operate correctly, the mapped region must begin exactly on a cache line boundary and end exactly on one (to prevent two separately mapped regions from sharing a single cache line). Therefore, it is recommended that driver writers who don't take special care to determine the cache line size at run time only map virtual regions that begin and end on page boundaries (which are guaranteed also to be cache line boundaries)." [1] This patch uses __get_free_pages instead of kzalloc to be sure that above will be true in all ARCHs and in all SLUBs debug configurations. [1] https://www.kernel.org/doc/Documentation/DMA-API.txt issue: 802618 Change-Id: Iee8176b183290213b1b4e66f1835f5c90f067075 Fixes: 1b2cd0fc673c ('IB/mlx4: Support the new memory registration API') Reported-by: Chuck Lever Signed-off-by: Christoph Hellwig Signed-off-by: Leon Romanovsky Signed-off-by: Yishai Hadas --- diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 6c5ac5d..4a8bbe4 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -139,7 +139,6 @@ u32 max_pages; struct mlx4_mr mmr; struct ib_umem *umem; - void *pages_alloc; }; struct mlx4_ib_mw { diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index 6312721..56b8d87 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -278,16 +278,12 @@ int max_pages) { int size = max_pages * sizeof(u64); - int add_size; int ret; - add_size = max_t(int, MLX4_MR_PAGES_ALIGN - ARCH_KMALLOC_MINALIGN, 0); - - mr->pages_alloc = kzalloc(size + add_size, GFP_KERNEL); - if (!mr->pages_alloc) + mr->pages = (__be64 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(size)); + if (!mr->pages) return -ENOMEM; - - mr->pages = PTR_ALIGN(mr->pages_alloc, MLX4_MR_PAGES_ALIGN); mr->page_map = dma_map_single(device->dma_device, mr->pages, size, DMA_TO_DEVICE); @@ -299,7 +295,7 @@ return 0; err: - kfree(mr->pages_alloc); + free_pages((unsigned long)mr->pages, get_order(size)); return ret; } @@ -313,7 +309,7 @@ dma_unmap_single(device->dma_device, mr->page_map, size, DMA_TO_DEVICE); - kfree(mr->pages_alloc); + free_pages((unsigned long)mr->pages, get_order(size)); mr->pages = NULL; } }