Commit 330caa51 authored by Federico Vaga's avatar Federico Vaga

drv: split DMA on mapping failure

By default the SW-IOMMU reserves 64MiB, but despite this it fails in
allocating buffere bigger than 0.3MiB. We do not have control over the
kernel code, and it is not clear how to debug it (e.g. see the current
status of those 64MiB). For this reasons the most practical solution
is to break the DMA transfer in smaller chunks until it works.

We set the minimum chunk to PAGE_SIZE, because if it fails with this,
really there is nothing we can do.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 9afa3d2e
......@@ -379,25 +379,37 @@ static int zfad_dma_prep_slave_sg(struct dma_chan *dchan,
if (err)
goto err_to_pages;
max_segment_size = dma_get_max_seg_size(dchan->device->dev);
max_segment_size = min(zfad_block->block->datalen + PAGE_SIZE, /* PAGE aligned */
(size_t)dma_get_max_seg_size(dchan->device->dev));
max_segment_size &= PAGE_MASK; /* to make alloc_table happy */
err = fa->sg_alloc_table_from_pages(&zfad_block->sgt, pages, nr_pages,
offset_in_page(zfad_block->block->data),
zfad_block->block->datalen,
max_segment_size, GFP_KERNEL);
if (unlikely(err))
goto err_sgt;
sg_mapped = dma_map_sg(&fa->pdev->dev,
zfad_block->sgt.sgl,
zfad_block->sgt.nents,
DMA_DEV_TO_MEM);
if (sg_mapped <= 0) {
err = sg_mapped ? sg_mapped : -ENOMEM;
/* Find something that fits in the [SW-]IOMMU */
do {
dev_dbg(&fa->pdev->dev, "DMA max segment %ld\n",
max_segment_size);
err = fa->sg_alloc_table_from_pages(&zfad_block->sgt, pages,
nr_pages,
offset_in_page(zfad_block->block->data),
zfad_block->block->datalen,
max_segment_size,
GFP_KERNEL);
if (unlikely(err))
goto err_sgt;
sg_mapped = dma_map_sg(&fa->pdev->dev,
zfad_block->sgt.sgl,
zfad_block->sgt.nents,
DMA_DEV_TO_MEM);
if (sg_mapped <= 0) {
sg_free_table(&zfad_block->sgt);
err = sg_mapped ? sg_mapped : -ENOMEM;
max_segment_size /= 2;
} else {
err = 0;
break;
}
} while (max_segment_size >= PAGE_SIZE);
if (err)
goto err_map;
}
/* Prepare the DMA transmisison */
tx = dmaengine_prep_slave_sg_ctx(dchan, zfad_block->sgt.sgl, sg_mapped,
DMA_DEV_TO_MEM, 0, zfad_block->dma_ctx);
......
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