[PATCH] staging: android: ion: Change dma_buf_kmap()/dma_buf_kmap_atomic() implementation
Alexey Skidanov
alexey.skidanov at intel.com
Mon Feb 12 22:33:53 UTC 2018
Current ion kernel mapping implementation uses vmap() to map previously
allocated buffers into kernel virtual address space.
On 32-bit platforms, vmap() might fail on large enough buffers due to the
limited available vmalloc space. dma_buf_kmap() should guarantee that
only one page is mapped at a time.
To fix this, kmap()/kmap_atomic() is used to implement the appropriate
interfaces.
Signed-off-by: Alexey Skidanov <alexey.skidanov at intel.com>
---
drivers/staging/android/ion/ion.c | 97 +++++++++++++++++++--------------------
drivers/staging/android/ion/ion.h | 1 -
2 files changed, 48 insertions(+), 50 deletions(-)
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 57e0d80..75830e3 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
+#include <linux/highmem.h>
#include "ion.h"
@@ -119,8 +120,6 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
void ion_buffer_destroy(struct ion_buffer *buffer)
{
- if (WARN_ON(buffer->kmap_cnt > 0))
- buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
buffer->heap->ops->free(buffer);
kfree(buffer);
}
@@ -140,34 +139,6 @@ static void _ion_buffer_destroy(struct ion_buffer *buffer)
ion_buffer_destroy(buffer);
}
-static void *ion_buffer_kmap_get(struct ion_buffer *buffer)
-{
- void *vaddr;
-
- if (buffer->kmap_cnt) {
- buffer->kmap_cnt++;
- return buffer->vaddr;
- }
- vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer);
- if (WARN_ONCE(!vaddr,
- "heap->ops->map_kernel should return ERR_PTR on error"))
- return ERR_PTR(-EINVAL);
- if (IS_ERR(vaddr))
- return vaddr;
- buffer->vaddr = vaddr;
- buffer->kmap_cnt++;
- return vaddr;
-}
-
-static void ion_buffer_kmap_put(struct ion_buffer *buffer)
-{
- buffer->kmap_cnt--;
- if (!buffer->kmap_cnt) {
- buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
- buffer->vaddr = NULL;
- }
-}
-
static struct sg_table *dup_sg_table(struct sg_table *table)
{
struct sg_table *new_table;
@@ -305,34 +276,68 @@ static void ion_dma_buf_release(struct dma_buf *dmabuf)
_ion_buffer_destroy(buffer);
}
+static inline int sg_page_count(struct scatterlist *sg)
+{
+ return PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT;
+}
+
+static struct page *ion_dma_buf_get_page(struct sg_table *sg_table,
+ unsigned long offset)
+{
+ struct page *page;
+ struct scatterlist *sg;
+ int i;
+ unsigned int nr_pages;
+
+ nr_pages = 0;
+ page = NULL;
+ /* Find the page with specified offset */
+ for_each_sg(sg_table->sgl, sg, sg_table->nents, i) {
+ if (nr_pages + sg_page_count(sg) > offset) {
+ page = nth_page(sg_page(sg), offset - nr_pages);
+ break;
+ }
+
+ nr_pages += sg_page_count(sg);
+ }
+
+ return page;
+}
static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset)
{
struct ion_buffer *buffer = dmabuf->priv;
- return buffer->vaddr + offset * PAGE_SIZE;
+ return kmap(ion_dma_buf_get_page(buffer->sg_table, offset));
}
static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
void *ptr)
{
+ kunmap(ptr);
+}
+
+static void *ion_dma_buf_kmap_atomic(struct dma_buf *dmabuf,
+ unsigned long offset)
+{
+ struct ion_buffer *buffer = dmabuf->priv;
+
+ return kmap_atomic(ion_dma_buf_get_page(buffer->sg_table,
+ offset));
+}
+
+static void ion_dma_buf_kunmap_atomic(struct dma_buf *dmabuf,
+ unsigned long offset,
+ void *ptr)
+{
+ kunmap_atomic(ptr);
}
static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
enum dma_data_direction direction)
{
struct ion_buffer *buffer = dmabuf->priv;
- void *vaddr;
struct ion_dma_buf_attachment *a;
- /*
- * TODO: Move this elsewhere because we don't always need a vaddr
- */
- if (buffer->heap->ops->map_kernel) {
- mutex_lock(&buffer->lock);
- vaddr = ion_buffer_kmap_get(buffer);
- mutex_unlock(&buffer->lock);
- }
-
mutex_lock(&buffer->lock);
list_for_each_entry(a, &buffer->attachments, list) {
dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents,
@@ -349,12 +354,6 @@ static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
struct ion_buffer *buffer = dmabuf->priv;
struct ion_dma_buf_attachment *a;
- if (buffer->heap->ops->map_kernel) {
- mutex_lock(&buffer->lock);
- ion_buffer_kmap_put(buffer);
- mutex_unlock(&buffer->lock);
- }
-
mutex_lock(&buffer->lock);
list_for_each_entry(a, &buffer->attachments, list) {
dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents,
@@ -374,8 +373,8 @@ static const struct dma_buf_ops dma_buf_ops = {
.detach = ion_dma_buf_detatch,
.begin_cpu_access = ion_dma_buf_begin_cpu_access,
.end_cpu_access = ion_dma_buf_end_cpu_access,
- .map_atomic = ion_dma_buf_kmap,
- .unmap_atomic = ion_dma_buf_kunmap,
+ .map_atomic = ion_dma_buf_kmap_atomic,
+ .unmap_atomic = ion_dma_buf_kunmap_atomic,
.map = ion_dma_buf_kmap,
.unmap = ion_dma_buf_kunmap,
};
diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
index a238f23..e2bbd74 100644
--- a/drivers/staging/android/ion/ion.h
+++ b/drivers/staging/android/ion/ion.h
@@ -72,7 +72,6 @@ struct ion_buffer {
size_t size;
void *priv_virt;
struct mutex lock;
- int kmap_cnt;
void *vaddr;
struct sg_table *sg_table;
struct list_head attachments;
--
2.7.4
More information about the devel
mailing list