summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
authorVandana Salve <vsalve@nvidia.com>2014-03-25 01:45:23 +0530
committerKrishna Reddy <vdumpa@nvidia.com>2014-03-27 16:03:34 -0700
commitdcee25f0c4e5da5f240ee550107a630847884ede (patch)
tree1d570401a6758c2d4a0fccd30b15e24aff0531e9 /drivers/base
parentb717da5b4cd3a207c10ba6e53b6e5d139d55f4d5 (diff)
dma: coherent: support residual memory chunk
Add support to handle alloc/release of residual memory chunk which is not multiple of cma_chunk_size bug 1473619 Change-Id: I9d5c777e376526b4a7944d5b8cd54785d631f031 Signed-off-by: Vandana Salve <vsalve@nvidia.com> Reviewed-on: http://git-master/r/385777 Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/dma-coherent.c89
1 files changed, 60 insertions, 29 deletions
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
index d45369857aef..47e791afea66 100644
--- a/drivers/base/dma-coherent.c
+++ b/drivers/base/dma-coherent.c
@@ -33,6 +33,7 @@ struct heap_info {
size_t len;
phys_addr_t cma_base;
size_t cma_len;
+ size_t rem_chunk_size;
struct dentry *dma_debug_root;
void (*update_resize_cfg)(phys_addr_t , size_t);
};
@@ -241,21 +242,16 @@ int dma_declare_coherent_resizable_cma_memory(struct device *dev,
err = -EINVAL;
goto fail;
}
- if (heap_info->cma_len % heap_info->cma_chunk_size) {
- dev_err(dev,
- "size is not multiple of cma_chunk_size(%zu)\n"
- "size truncated from %zu to %zu\n",
- heap_info->cma_chunk_size, heap_info->cma_len,
- round_down(heap_info->cma_len,
- heap_info->cma_chunk_size));
- heap_info->cma_len = round_down(
- heap_info->cma_len,
- heap_info->cma_chunk_size);
- }
mutex_init(&heap_info->resize_lock);
- heap_info->num_devs = div_u64(heap_info->cma_len,
- heap_info->cma_chunk_size);
+ heap_info->num_devs = div_u64_rem(heap_info->cma_len,
+ heap_info->cma_chunk_size, &heap_info->rem_chunk_size);
+ if (heap_info->rem_chunk_size) {
+ heap_info->num_devs++;
+ dev_dbg(dev, "size is not multiple of cma_chunk_size\n"
+ "heap_info->num_devs (%d) rem_chunk_size(%d)\n",
+ heap_info->num_devs, heap_info->rem_chunk_size);
+ }
heap_info->devs = dma_create_dma_devs(dma_info->name,
heap_info->num_devs);
if (!heap_info->devs) {
@@ -292,6 +288,13 @@ static phys_addr_t alloc_from_contiguous_heap(
struct page *page;
unsigned long order;
+ /* check for if last chunk is residual chunk */
+ if (h->len && (h->dev_end + 1 == (h->num_devs - 1))
+ && h->rem_chunk_size) {
+ len = h->rem_chunk_size;
+ dev_dbg(h->cma_dev, "rem_chunk_size (%d)\n", len);
+ }
+
order = get_order(len);
count = PAGE_ALIGN(len) >> PAGE_SHIFT;
page = dma_alloc_from_contiguous(h->cma_dev, count, order);
@@ -325,6 +328,7 @@ static int heap_resize_locked(struct heap_info *h)
int idx;
phys_addr_t base;
bool at_bottom = false;
+ size_t cma_chunk_size = h->cma_chunk_size;
base = alloc_from_contiguous_heap(h, 0, h->cma_chunk_size);
if (dma_mapping_error(h->cma_dev, base))
@@ -339,24 +343,32 @@ static int heap_resize_locked(struct heap_info *h)
goto fail_non_contig;
BUG_ON(h->dev_start - 1 != idx && h->dev_end + 1 != idx && h->len);
- dev_dbg(&h->devs[idx],
- "Resize VPR base from=0x%pa to=0x%pa, len from=%zu to=%zu\n",
- &h->base, &base, h->len, h->len + h->cma_chunk_size);
+ if (h->len && (h->dev_end + 1 == (h->num_devs - 1))
+ && h->rem_chunk_size) {
+ cma_chunk_size = h->rem_chunk_size;
+ dev_dbg(h->cma_dev, "rem_chunk_size (%d)\n", cma_chunk_size);
+ }
- if (declare_coherent_heap(&h->devs[idx], base, h->cma_chunk_size))
+ if (declare_coherent_heap(&h->devs[idx], base, cma_chunk_size))
goto fail_declare;
- dev_dbg(&h->devs[idx],
- "Resize VPR base from=0x%pa to=0x%pa, len from=%zu to=%zu\n",
- &h->base, &base, h->len, h->len + h->cma_chunk_size);
+
if (at_bottom) {
h->base = base;
h->dev_start = idx;
if (!h->len)
h->dev_end = h->dev_start;
+ dev_dbg(&h->devs[idx],
+ "Resize VPR base from=0x%pa to=0x%pa,"
+ " len from=%zu to=%zu\n",
+ &h->base, &base, h->len, h->len + cma_chunk_size);
} else {
h->dev_end = idx;
+ dev_dbg(&h->devs[idx],
+ "Resize VPR base 0x%pa len from=%zu to=%zu\n",
+ &h->base, h->len, h->len + cma_chunk_size);
}
- h->len += h->cma_chunk_size;
+
+ h->len += cma_chunk_size;
/* Handle VPR configuration updates*/
if (h->update_resize_cfg)
h->update_resize_cfg(h->base, h->len);
@@ -365,7 +377,7 @@ static int heap_resize_locked(struct heap_info *h)
fail_non_contig:
dev_dbg(&h->devs[idx], "Found Non-Contiguous block(0x%pa)\n", &base);
fail_declare:
- release_from_contiguous_heap(h, base, h->cma_chunk_size);
+ release_from_contiguous_heap(h, base, cma_chunk_size);
return 1;
}
@@ -520,6 +532,7 @@ static int dma_release_from_coherent_heap_dev(struct device *dev, size_t len,
void *ret = NULL;
dma_addr_t dev_base;
struct heap_info *h = NULL;
+ size_t cma_chunk_size = h->cma_chunk_size;
if (!dma_is_coherent_dev(dev))
return 0;
@@ -546,16 +559,24 @@ static int dma_release_from_coherent_heap_dev(struct device *dev, size_t len,
check_next_chunk:
/* Check if heap can be shrinked */
if ((idx == h->dev_start || idx == h->dev_end) && h->len) {
- /* check if entire chunk is free */
+ /* check if entire chunk is free
+ * check if last chunk is residual chunk
+ */
+ if ((idx == h->num_devs - 1) && h->rem_chunk_size) {
+ cma_chunk_size = h->rem_chunk_size;
+ dev_dbg(&h->devs[idx], "rem chunk size (%d)\n",
+ h->rem_chunk_size);
+ } else
+ cma_chunk_size = h->cma_chunk_size;
+
resize_err = dma_alloc_from_coherent_dev(&h->devs[idx],
- h->cma_chunk_size,
+ cma_chunk_size,
&dev_base, &ret, attrs);
if (!resize_err)
goto out_unlock;
else {
resize_err = dma_release_from_coherent_dev(
- &h->devs[idx],
- h->cma_chunk_size,
+ &h->devs[idx], cma_chunk_size,
(void *)dev_base, attrs);
if (!resize_err)
goto out_unlock;
@@ -563,18 +584,28 @@ check_next_chunk:
dma_release_declared_memory(
&h->devs[idx]);
BUG_ON(h->devs[idx].dma_mem != NULL);
- h->len -= h->cma_chunk_size;
+ h->len -= cma_chunk_size;
if ((idx == h->dev_start)) {
- h->base += h->cma_chunk_size;
+ h->base += cma_chunk_size;
h->dev_start++;
dev_dbg(&h->devs[idx],
"Release Chunk at bottom\n");
+ dev_dbg(&h->devs[idx],
+ "Resize VPR base from=0x%pa to=0x%pa,"
+ " len from=%zu to=%zu\n",
+ &h->base - cma_chunk_size, &h->base,
+ h->len + cma_chunk_size, h->len);
idx++;
} else {
h->dev_end--;
dev_dbg(&h->devs[idx],
"Release Chunk at top\n");
+ dev_dbg(&h->devs[idx],
+ "Resize VPR base %pa,"
+ " len from=%zu to=%zu\n",
+ &h->base,
+ h->len + cma_chunk_size, h->len);
idx--;
}
@@ -582,7 +613,7 @@ check_next_chunk:
if (h->update_resize_cfg)
h->update_resize_cfg(h->base, h->len);
release_from_contiguous_heap(h,
- dev_base, h->cma_chunk_size);
+ dev_base, cma_chunk_size);
}
goto check_next_chunk;
}