aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei Hu\(Xavier\) <xavier.huwei@huawei.com>2017-11-28 02:10:27 -0500
committerJason Gunthorpe <jgg@mellanox.com>2017-12-01 14:21:27 -0500
commitb1c158350968d6717ec1889f07ea3a89432e8574 (patch)
treeed2aef3f6cce7be029ac48b4cb2e202c068bd85f
parentdb270c41900d39a388990701da3ee2971094ebaa (diff)
RDMA/hns: Get rid of virt_to_page and vmap calls after dma_alloc_coherent
In general dma_alloc_coherent() returns a CPU virtual address and a DMA address, and we have no guarantee that the virtual address is either in the linear map or vmalloc. It could be in some other special place. We have no guarantee that the underlying memory even has an associated struct page at all. In current code, there are incorrect usage as below: dma_alloc_coherent + virt_to_page + vmap. There will probably introduce coherency problem. This patch fixes it to get rid of virt_to_page and vmap calls at Leon's suggestion. The related link: https://lkml.org/lkml/2017/11/7/34 Fixes: 9a44353("IB/hns: Add driver files for hns RoCE driver") Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com> Signed-off-by: Shaobo Xu <xushaobo2@huawei.com> Signed-off-by: Lijun Ou <oulijun@huawei.com> Signed-off-by: Yixian Liu <liuyixian@huawei.com> Signed-off-by: Xiping Zhang (Francis) <zhangxiping3@huawei.com> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_alloc.c23
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_device.h4
2 files changed, 1 insertions, 26 deletions
diff --git a/drivers/infiniband/hw/hns/hns_roce_alloc.c b/drivers/infiniband/hw/hns/hns_roce_alloc.c
index 3e4c5253ab5c..a40ec939ece5 100644
--- a/drivers/infiniband/hw/hns/hns_roce_alloc.c
+++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c
@@ -162,14 +162,10 @@ void hns_roce_buf_free(struct hns_roce_dev *hr_dev, u32 size,
162{ 162{
163 int i; 163 int i;
164 struct device *dev = hr_dev->dev; 164 struct device *dev = hr_dev->dev;
165 u32 bits_per_long = BITS_PER_LONG;
166 165
167 if (buf->nbufs == 1) { 166 if (buf->nbufs == 1) {
168 dma_free_coherent(dev, size, buf->direct.buf, buf->direct.map); 167 dma_free_coherent(dev, size, buf->direct.buf, buf->direct.map);
169 } else { 168 } else {
170 if (bits_per_long == 64 && buf->page_shift == PAGE_SHIFT)
171 vunmap(buf->direct.buf);
172
173 for (i = 0; i < buf->nbufs; ++i) 169 for (i = 0; i < buf->nbufs; ++i)
174 if (buf->page_list[i].buf) 170 if (buf->page_list[i].buf)
175 dma_free_coherent(dev, 1 << buf->page_shift, 171 dma_free_coherent(dev, 1 << buf->page_shift,
@@ -185,9 +181,7 @@ int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
185{ 181{
186 int i = 0; 182 int i = 0;
187 dma_addr_t t; 183 dma_addr_t t;
188 struct page **pages;
189 struct device *dev = hr_dev->dev; 184 struct device *dev = hr_dev->dev;
190 u32 bits_per_long = BITS_PER_LONG;
191 u32 page_size = 1 << page_shift; 185 u32 page_size = 1 << page_shift;
192 u32 order; 186 u32 order;
193 187
@@ -236,23 +230,6 @@ int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
236 buf->page_list[i].map = t; 230 buf->page_list[i].map = t;
237 memset(buf->page_list[i].buf, 0, page_size); 231 memset(buf->page_list[i].buf, 0, page_size);
238 } 232 }
239 if (bits_per_long == 64 && page_shift == PAGE_SHIFT) {
240 pages = kmalloc_array(buf->nbufs, sizeof(*pages),
241 GFP_KERNEL);
242 if (!pages)
243 goto err_free;
244
245 for (i = 0; i < buf->nbufs; ++i)
246 pages[i] = virt_to_page(buf->page_list[i].buf);
247
248 buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP,
249 PAGE_KERNEL);
250 kfree(pages);
251 if (!buf->direct.buf)
252 goto err_free;
253 } else {
254 buf->direct.buf = NULL;
255 }
256 } 233 }
257 234
258 return 0; 235 return 0;
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
index 01d3d695cbba..b154ce40cded 100644
--- a/drivers/infiniband/hw/hns/hns_roce_device.h
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -726,11 +726,9 @@ static inline struct hns_roce_qp
726 726
727static inline void *hns_roce_buf_offset(struct hns_roce_buf *buf, int offset) 727static inline void *hns_roce_buf_offset(struct hns_roce_buf *buf, int offset)
728{ 728{
729 u32 bits_per_long_val = BITS_PER_LONG;
730 u32 page_size = 1 << buf->page_shift; 729 u32 page_size = 1 << buf->page_shift;
731 730
732 if ((bits_per_long_val == 64 && buf->page_shift == PAGE_SHIFT) || 731 if (buf->nbufs == 1)
733 buf->nbufs == 1)
734 return (char *)(buf->direct.buf) + offset; 732 return (char *)(buf->direct.buf) + offset;
735 else 733 else
736 return (char *)(buf->page_list[offset >> buf->page_shift].buf) + 734 return (char *)(buf->page_list[offset >> buf->page_shift].buf) +