Commit 99a06056 authored by Jiasen Lin's avatar Jiasen Lin Committed by Jon Mason

NTB: ntb_perf: Fix address err in perf_copy_chunk

peer->outbuf is a virtual address which is get by ioremap, it can not
be converted to a physical address by virt_to_page and page_to_phys.
This conversion will result in DMA error, because the destination address
which is converted by page_to_phys is invalid.

This patch save the MMIO address of NTB BARx in perf_setup_peer_mw,
and map the BAR space to DMA address after we assign the DMA channel.
Then fill the destination address of DMA descriptor with this DMA address
to guarantee that the address of memory write requests fall into
memory window of NBT BARx with IOMMU enabled and disabled.

Fixes: 5648e56d ("NTB: ntb_perf: Add full multi-port NTB API support")
Signed-off-by: default avatarJiasen Lin <linjiasen@hygon.cn>
Reviewed-by: default avatarLogan Gunthorpe <logang@deltatee.com>
Signed-off-by: default avatarJon Mason <jdmason@kudzu.us>
parent bb81bf62
...@@ -149,7 +149,8 @@ struct perf_peer { ...@@ -149,7 +149,8 @@ struct perf_peer {
u64 outbuf_xlat; u64 outbuf_xlat;
resource_size_t outbuf_size; resource_size_t outbuf_size;
void __iomem *outbuf; void __iomem *outbuf;
phys_addr_t out_phys_addr;
dma_addr_t dma_dst_addr;
/* Inbound MW params */ /* Inbound MW params */
dma_addr_t inbuf_xlat; dma_addr_t inbuf_xlat;
resource_size_t inbuf_size; resource_size_t inbuf_size;
...@@ -782,6 +783,10 @@ static int perf_copy_chunk(struct perf_thread *pthr, ...@@ -782,6 +783,10 @@ static int perf_copy_chunk(struct perf_thread *pthr,
struct dmaengine_unmap_data *unmap; struct dmaengine_unmap_data *unmap;
struct device *dma_dev; struct device *dma_dev;
int try = 0, ret = 0; int try = 0, ret = 0;
struct perf_peer *peer = pthr->perf->test_peer;
void __iomem *vbase;
void __iomem *dst_vaddr;
dma_addr_t dst_dma_addr;
if (!use_dma) { if (!use_dma) {
memcpy_toio(dst, src, len); memcpy_toio(dst, src, len);
...@@ -794,6 +799,10 @@ static int perf_copy_chunk(struct perf_thread *pthr, ...@@ -794,6 +799,10 @@ static int perf_copy_chunk(struct perf_thread *pthr,
offset_in_page(dst), len)) offset_in_page(dst), len))
return -EIO; return -EIO;
vbase = peer->outbuf;
dst_vaddr = dst;
dst_dma_addr = peer->dma_dst_addr + (dst_vaddr - vbase);
unmap = dmaengine_get_unmap_data(dma_dev, 2, GFP_NOWAIT); unmap = dmaengine_get_unmap_data(dma_dev, 2, GFP_NOWAIT);
if (!unmap) if (!unmap)
return -ENOMEM; return -ENOMEM;
...@@ -807,8 +816,7 @@ static int perf_copy_chunk(struct perf_thread *pthr, ...@@ -807,8 +816,7 @@ static int perf_copy_chunk(struct perf_thread *pthr,
} }
unmap->to_cnt = 1; unmap->to_cnt = 1;
unmap->addr[1] = dma_map_page(dma_dev, virt_to_page(dst), unmap->addr[1] = dst_dma_addr;
offset_in_page(dst), len, DMA_FROM_DEVICE);
if (dma_mapping_error(dma_dev, unmap->addr[1])) { if (dma_mapping_error(dma_dev, unmap->addr[1])) {
ret = -EIO; ret = -EIO;
goto err_free_resource; goto err_free_resource;
...@@ -865,6 +873,7 @@ static int perf_init_test(struct perf_thread *pthr) ...@@ -865,6 +873,7 @@ static int perf_init_test(struct perf_thread *pthr)
{ {
struct perf_ctx *perf = pthr->perf; struct perf_ctx *perf = pthr->perf;
dma_cap_mask_t dma_mask; dma_cap_mask_t dma_mask;
struct perf_peer *peer = pthr->perf->test_peer;
pthr->src = kmalloc_node(perf->test_peer->outbuf_size, GFP_KERNEL, pthr->src = kmalloc_node(perf->test_peer->outbuf_size, GFP_KERNEL,
dev_to_node(&perf->ntb->dev)); dev_to_node(&perf->ntb->dev));
...@@ -882,15 +891,33 @@ static int perf_init_test(struct perf_thread *pthr) ...@@ -882,15 +891,33 @@ static int perf_init_test(struct perf_thread *pthr)
if (!pthr->dma_chan) { if (!pthr->dma_chan) {
dev_err(&perf->ntb->dev, "%d: Failed to get DMA channel\n", dev_err(&perf->ntb->dev, "%d: Failed to get DMA channel\n",
pthr->tidx); pthr->tidx);
atomic_dec(&perf->tsync); goto err_free;
wake_up(&perf->twait);
kfree(pthr->src);
return -ENODEV;
} }
peer->dma_dst_addr =
dma_map_resource(pthr->dma_chan->device->dev,
peer->out_phys_addr, peer->outbuf_size,
DMA_FROM_DEVICE, 0);
if (dma_mapping_error(pthr->dma_chan->device->dev,
peer->dma_dst_addr)) {
dev_err(pthr->dma_chan->device->dev, "%d: Failed to map DMA addr\n",
pthr->tidx);
peer->dma_dst_addr = 0;
dma_release_channel(pthr->dma_chan);
goto err_free;
}
dev_dbg(pthr->dma_chan->device->dev, "%d: Map MMIO %pa to DMA addr %pad\n",
pthr->tidx,
&peer->out_phys_addr,
&peer->dma_dst_addr);
atomic_set(&pthr->dma_sync, 0); atomic_set(&pthr->dma_sync, 0);
return 0; return 0;
err_free:
atomic_dec(&perf->tsync);
wake_up(&perf->twait);
kfree(pthr->src);
return -ENODEV;
} }
static int perf_run_test(struct perf_thread *pthr) static int perf_run_test(struct perf_thread *pthr)
...@@ -978,8 +1005,13 @@ static void perf_clear_test(struct perf_thread *pthr) ...@@ -978,8 +1005,13 @@ static void perf_clear_test(struct perf_thread *pthr)
* We call it anyway just to be sure of the transfers completion. * We call it anyway just to be sure of the transfers completion.
*/ */
(void)dmaengine_terminate_sync(pthr->dma_chan); (void)dmaengine_terminate_sync(pthr->dma_chan);
if (pthr->perf->test_peer->dma_dst_addr)
dma_release_channel(pthr->dma_chan); dma_unmap_resource(pthr->dma_chan->device->dev,
pthr->perf->test_peer->dma_dst_addr,
pthr->perf->test_peer->outbuf_size,
DMA_FROM_DEVICE, 0);
if (pthr->dma_chan)
dma_release_channel(pthr->dma_chan);
no_dma_notify: no_dma_notify:
atomic_dec(&perf->tsync); atomic_dec(&perf->tsync);
...@@ -1194,6 +1226,9 @@ static ssize_t perf_dbgfs_read_info(struct file *filep, char __user *ubuf, ...@@ -1194,6 +1226,9 @@ static ssize_t perf_dbgfs_read_info(struct file *filep, char __user *ubuf,
pos += scnprintf(buf + pos, buf_size - pos, pos += scnprintf(buf + pos, buf_size - pos,
"\tOut buffer addr 0x%pK\n", peer->outbuf); "\tOut buffer addr 0x%pK\n", peer->outbuf);
pos += scnprintf(buf + pos, buf_size - pos,
"\tOut buff phys addr %pa[p]\n", &peer->out_phys_addr);
pos += scnprintf(buf + pos, buf_size - pos, pos += scnprintf(buf + pos, buf_size - pos,
"\tOut buffer size %pa\n", &peer->outbuf_size); "\tOut buffer size %pa\n", &peer->outbuf_size);
...@@ -1388,6 +1423,8 @@ static int perf_setup_peer_mw(struct perf_peer *peer) ...@@ -1388,6 +1423,8 @@ static int perf_setup_peer_mw(struct perf_peer *peer)
if (!peer->outbuf) if (!peer->outbuf)
return -ENOMEM; return -ENOMEM;
peer->out_phys_addr = phys_addr;
if (max_mw_size && peer->outbuf_size > max_mw_size) { if (max_mw_size && peer->outbuf_size > max_mw_size) {
peer->outbuf_size = max_mw_size; peer->outbuf_size = max_mw_size;
dev_warn(&peer->perf->ntb->dev, dev_warn(&peer->perf->ntb->dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment