Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14455503 authored by Sandeep Patil's avatar Sandeep Patil Committed by Alistair Delva
Browse files

staging: ion: refactor ion's dmabuf manipulators into a separate file.



This patch is preparatory work for making ion heaps modular. The patch
itself doesn't make any significant changes except for re-organizing the
buffer manipulator functions in a single file. This will be helpful
later when we specifically export some of these functions to be used by
a heap module.

Bug: 133508579
Test: ion-unit-tests

Change-Id: I52ecea78a179c936006a21beb7630009984cb22f
Co-developed-by: default avatarIsaac J. Manjarres <isaacm@codeaurora.org>
Signed-off-by: default avatarSandeep Patil <sspatil@google.com>
parent d6aced53
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_ION) += ion.o ion_buffer.o ion_heap.o
obj-$(CONFIG_ION) += ion.o ion_buffer.o ion_dma_buf.o ion_heap.o
obj-$(CONFIG_ION_SYSTEM_HEAP) += ion_system_heap.o ion_page_pool.o
obj-$(CONFIG_ION_SYSTEM_HEAP) += ion_system_heap.o ion_page_pool.o
obj-$(CONFIG_ION_CMA_HEAP) += ion_cma_heap.o
obj-$(CONFIG_ION_CMA_HEAP) += ion_cma_heap.o
+8 −246
Original line number Original line Diff line number Diff line
@@ -17,268 +17,30 @@
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/kthread.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/mm_types.h>
#include <linux/rbtree.h>
#include <linux/rbtree.h>
#include <linux/sched/task.h>
#include <linux/sched/task.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>


#include "ion_private.h"
#include "ion_private.h"


static struct ion_device *internal_dev;
static struct ion_device *internal_dev;
static int heap_id;
static int heap_id;


static struct sg_table *dup_sg_table(struct sg_table *table)
/* Entry into ION allocator for rest of the kernel */
{
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask,
	struct sg_table *new_table;
	int ret, i;
	struct scatterlist *sg, *new_sg;

	new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
	if (!new_table)
		return ERR_PTR(-ENOMEM);

	ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
	if (ret) {
		kfree(new_table);
		return ERR_PTR(-ENOMEM);
	}

	new_sg = new_table->sgl;
	for_each_sg(table->sgl, sg, table->nents, i) {
		memcpy(new_sg, sg, sizeof(*sg));
		new_sg->dma_address = 0;
		new_sg = sg_next(new_sg);
	}

	return new_table;
}

static void free_duped_table(struct sg_table *table)
{
	sg_free_table(table);
	kfree(table);
}

struct ion_dma_buf_attachment {
	struct device *dev;
	struct sg_table *table;
	struct list_head list;
};

static int ion_dma_buf_attach(struct dma_buf *dmabuf,
			      struct dma_buf_attachment *attachment)
{
	struct ion_dma_buf_attachment *a;
	struct sg_table *table;
	struct ion_buffer *buffer = dmabuf->priv;

	a = kzalloc(sizeof(*a), GFP_KERNEL);
	if (!a)
		return -ENOMEM;

	table = dup_sg_table(buffer->sg_table);
	if (IS_ERR(table)) {
		kfree(a);
		return -ENOMEM;
	}

	a->table = table;
	a->dev = attachment->dev;
	INIT_LIST_HEAD(&a->list);

	attachment->priv = a;

	mutex_lock(&buffer->lock);
	list_add(&a->list, &buffer->attachments);
	mutex_unlock(&buffer->lock);

	return 0;
}

static void ion_dma_buf_detatch(struct dma_buf *dmabuf,
				struct dma_buf_attachment *attachment)
{
	struct ion_dma_buf_attachment *a = attachment->priv;
	struct ion_buffer *buffer = dmabuf->priv;

	mutex_lock(&buffer->lock);
	list_del(&a->list);
	mutex_unlock(&buffer->lock);
	free_duped_table(a->table);

	kfree(a);
}

static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
					enum dma_data_direction direction)
{
	struct ion_dma_buf_attachment *a = attachment->priv;
	struct sg_table *table;

	table = a->table;

	if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
			direction))
		return ERR_PTR(-ENOMEM);

	return table;
}

static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment,
			      struct sg_table *table,
			      enum dma_data_direction direction)
{
	dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction);
}

static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{
	struct ion_buffer *buffer = dmabuf->priv;
	int ret = 0;

	if (!buffer->heap->ops->map_user) {
		pr_err("%s: this heap does not define a method for mapping to userspace\n",
		       __func__);
		return -EINVAL;
	}

	if (!(buffer->flags & ION_FLAG_CACHED))
		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);

	mutex_lock(&buffer->lock);
	/* now map it to userspace */
	ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma);
	mutex_unlock(&buffer->lock);

	if (ret)
		pr_err("%s: failure mapping buffer to userspace\n",
		       __func__);

	return ret;
}

static void ion_dma_buf_release(struct dma_buf *dmabuf)
{
	struct ion_buffer *buffer = dmabuf->priv;

	ion_buffer_destroy(internal_dev, buffer);
}

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;
}

static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
			       void *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;
	int ret = 0;

	/*
	 * 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);
		if (IS_ERR(vaddr)) {
			ret = PTR_ERR(vaddr);
			goto unlock;
		}
		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,
				    direction);
	}

unlock:
	mutex_unlock(&buffer->lock);
	return ret;
}

static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
				      enum dma_data_direction direction)
{
	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,
				       direction);
	}
	mutex_unlock(&buffer->lock);

	return 0;
}

static const struct dma_buf_ops dma_buf_ops = {
	.map_dma_buf = ion_map_dma_buf,
	.unmap_dma_buf = ion_unmap_dma_buf,
	.mmap = ion_mmap,
	.release = ion_dma_buf_release,
	.attach = ion_dma_buf_attach,
	.detach = ion_dma_buf_detatch,
	.begin_cpu_access = ion_dma_buf_begin_cpu_access,
	.end_cpu_access = ion_dma_buf_end_cpu_access,
	.map = ion_dma_buf_kmap,
	.unmap = ion_dma_buf_kunmap,
};

static struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask,
			  unsigned int flags)
			  unsigned int flags)
{
{
	struct ion_buffer *buffer;
	return ion_dmabuf_alloc(internal_dev, len, heap_id_mask, flags);
	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
	struct dma_buf *dmabuf;

	pr_debug("%s: len %zu heap_id_mask %u flags %x\n", __func__,
		 len, heap_id_mask, flags);

	buffer = ion_buffer_alloc(internal_dev, len, heap_id_mask, flags);
	if (IS_ERR(buffer))
		return ERR_CAST(buffer);

	exp_info.ops = &dma_buf_ops;
	exp_info.size = buffer->size;
	exp_info.flags = O_RDWR;
	exp_info.priv = buffer;

	dmabuf = dma_buf_export(&exp_info);
	if (IS_ERR(dmabuf))
		ion_buffer_destroy(internal_dev, buffer);

	return dmabuf;
}
}
EXPORT_SYMBOL_GPL(ion_alloc);


struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask,
int ion_free(struct ion_buffer *buffer)
			  unsigned int flags)
{
{
	return ion_alloc_dmabuf(len, heap_id_mask, flags);
	return ion_buffer_destroy(internal_dev, buffer);
}
}
EXPORT_SYMBOL_GPL(ion_alloc);


static int ion_alloc_fd(size_t len, unsigned int heap_id_mask,
static int ion_alloc_fd(size_t len, unsigned int heap_id_mask,
			unsigned int flags)
			unsigned int flags)
@@ -286,7 +48,7 @@ static int ion_alloc_fd(size_t len, unsigned int heap_id_mask,
	int fd;
	int fd;
	struct dma_buf *dmabuf;
	struct dma_buf *dmabuf;


	dmabuf = ion_alloc_dmabuf(len, heap_id_mask, flags);
	dmabuf = ion_dmabuf_alloc(internal_dev, len, heap_id_mask, flags);
	if (IS_ERR(dmabuf))
	if (IS_ERR(dmabuf))
		return PTR_ERR(dmabuf);
		return PTR_ERR(dmabuf);


+4 −2
Original line number Original line Diff line number Diff line
@@ -149,13 +149,13 @@ void ion_buffer_release(struct ion_buffer *buffer)
	kfree(buffer);
	kfree(buffer);
}
}


void ion_buffer_destroy(struct ion_device *dev, struct ion_buffer *buffer)
int ion_buffer_destroy(struct ion_device *dev, struct ion_buffer *buffer)
{
{
	struct ion_heap *heap;
	struct ion_heap *heap;


	if (!dev || !buffer) {
	if (!dev || !buffer) {
		pr_warn("%s: invalid argument\n", __func__);
		pr_warn("%s: invalid argument\n", __func__);
		return;
		return -EINVAL;
	}
	}


	heap = buffer->heap;
	heap = buffer->heap;
@@ -167,6 +167,8 @@ void ion_buffer_destroy(struct ion_device *dev, struct ion_buffer *buffer)
		ion_heap_freelist_add(heap, buffer);
		ion_heap_freelist_add(heap, buffer);
	else
	else
		ion_buffer_release(buffer);
		ion_buffer_release(buffer);

	return 0;
}
}


void *ion_buffer_kmap_get(struct ion_buffer *buffer)
void *ion_buffer_kmap_get(struct ion_buffer *buffer)
+252 −0
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * ION Memory Allocator - dmabuf interface
 *
 * Copyright (c) 2019, Google, Inc.
 */

#include <linux/device.h>
#include <linux/dma-buf.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>

#include "ion_private.h"

static struct sg_table *dup_sg_table(struct sg_table *table)
{
	struct sg_table *new_table;
	int ret, i;
	struct scatterlist *sg, *new_sg;

	new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
	if (!new_table)
		return ERR_PTR(-ENOMEM);

	ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
	if (ret) {
		kfree(new_table);
		return ERR_PTR(-ENOMEM);
	}

	new_sg = new_table->sgl;
	for_each_sg(table->sgl, sg, table->nents, i) {
		memcpy(new_sg, sg, sizeof(*sg));
		new_sg->dma_address = 0;
		new_sg = sg_next(new_sg);
	}

	return new_table;
}

static void free_duped_table(struct sg_table *table)
{
	sg_free_table(table);
	kfree(table);
}

struct ion_dma_buf_attachment {
	struct device *dev;
	struct sg_table *table;
	struct list_head list;
};

static int ion_dma_buf_attach(struct dma_buf *dmabuf,
			      struct dma_buf_attachment *attachment)
{
	struct ion_dma_buf_attachment *a;
	struct sg_table *table;
	struct ion_buffer *buffer = dmabuf->priv;

	a = kzalloc(sizeof(*a), GFP_KERNEL);
	if (!a)
		return -ENOMEM;

	table = dup_sg_table(buffer->sg_table);
	if (IS_ERR(table)) {
		kfree(a);
		return -ENOMEM;
	}

	a->table = table;
	a->dev = attachment->dev;
	INIT_LIST_HEAD(&a->list);

	attachment->priv = a;

	mutex_lock(&buffer->lock);
	list_add(&a->list, &buffer->attachments);
	mutex_unlock(&buffer->lock);

	return 0;
}

static void ion_dma_buf_detatch(struct dma_buf *dmabuf,
				struct dma_buf_attachment *attachment)
{
	struct ion_dma_buf_attachment *a = attachment->priv;
	struct ion_buffer *buffer = dmabuf->priv;

	mutex_lock(&buffer->lock);
	list_del(&a->list);
	mutex_unlock(&buffer->lock);
	free_duped_table(a->table);

	kfree(a);
}

static struct sg_table *ion_dma_buf_map(struct dma_buf_attachment *attachment,
					enum dma_data_direction direction)
{
	struct ion_dma_buf_attachment *a = attachment->priv;
	struct sg_table *table;

	table = a->table;

	if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
			direction))
		return ERR_PTR(-ENOMEM);

	return table;
}

static void ion_dma_buf_unmap(struct dma_buf_attachment *attachment,
			      struct sg_table *table,
			      enum dma_data_direction direction)
{
	dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction);
}

static int ion_dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{
	struct ion_buffer *buffer = dmabuf->priv;
	int ret = 0;

	if (!buffer->heap->ops->map_user) {
		pr_err("%s: this heap does not define a method for mapping to userspace\n",
		       __func__);
		return -EINVAL;
	}

	if (!(buffer->flags & ION_FLAG_CACHED))
		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);

	mutex_lock(&buffer->lock);
	/* now map it to userspace */
	ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma);
	mutex_unlock(&buffer->lock);

	if (ret)
		pr_err("%s: failure mapping buffer to userspace\n",
		       __func__);

	return ret;
}

static void ion_dma_buf_release(struct dma_buf *dmabuf)
{
	struct ion_buffer *buffer = dmabuf->priv;

	ion_free(buffer);
}

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;
}

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;
	int ret = 0;

	/*
	 * 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);
		if (IS_ERR(vaddr)) {
			ret = PTR_ERR(vaddr);
			goto unlock;
		}
		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,
				    direction);
	}

unlock:
	mutex_unlock(&buffer->lock);
	return ret;
}

static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
				      enum dma_data_direction direction)
{
	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,
				       direction);
	}
	mutex_unlock(&buffer->lock);

	return 0;
}

static const struct dma_buf_ops dma_buf_ops = {
	.map_dma_buf = ion_dma_buf_map,
	.unmap_dma_buf = ion_dma_buf_unmap,
	.mmap = ion_dma_buf_mmap,
	.release = ion_dma_buf_release,
	.attach = ion_dma_buf_attach,
	.detach = ion_dma_buf_detatch,
	.begin_cpu_access = ion_dma_buf_begin_cpu_access,
	.end_cpu_access = ion_dma_buf_end_cpu_access,
	.map = ion_dma_buf_kmap,
};

struct dma_buf *ion_dmabuf_alloc(struct ion_device *dev, size_t len,
				 unsigned int heap_id_mask,
				 unsigned int flags)
{
	struct ion_buffer *buffer;
	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
	struct dma_buf *dmabuf;

	pr_debug("%s: len %zu heap_id_mask %u flags %x\n", __func__,
		 len, heap_id_mask, flags);

	buffer = ion_buffer_alloc(dev, len, heap_id_mask, flags);
	if (IS_ERR(buffer))
		return ERR_CAST(buffer);

	exp_info.ops = &dma_buf_ops;
	exp_info.size = buffer->size;
	exp_info.flags = O_RDWR;
	exp_info.priv = buffer;

	dmabuf = dma_buf_export(&exp_info);
	if (IS_ERR(dmabuf))
		ion_buffer_destroy(dev, buffer);

	return dmabuf;
}
+10 −1
Original line number Original line Diff line number Diff line
@@ -9,6 +9,7 @@
#define _ION_PRIVATE_H
#define _ION_PRIVATE_H


#include <linux/dcache.h>
#include <linux/dcache.h>
#include <linux/dma-buf.h>
#include <linux/miscdevice.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/plist.h>
#include <linux/plist.h>
@@ -40,8 +41,16 @@ extern struct ion_buffer *ion_buffer_alloc(struct ion_device *dev, size_t len,
					   unsigned int heap_id_mask,
					   unsigned int heap_id_mask,
					   unsigned int flags);
					   unsigned int flags);
extern void ion_buffer_release(struct ion_buffer *buffer);
extern void ion_buffer_release(struct ion_buffer *buffer);
extern void ion_buffer_destroy(struct ion_device *dev, struct ion_buffer *buffer);
extern int ion_buffer_destroy(struct ion_device *dev,
			      struct ion_buffer *buffer);
extern void *ion_buffer_kmap_get(struct ion_buffer *buffer);
extern void *ion_buffer_kmap_get(struct ion_buffer *buffer);
extern void ion_buffer_kmap_put(struct ion_buffer *buffer);
extern void ion_buffer_kmap_put(struct ion_buffer *buffer);


/* ion dmabuf allocator */
extern struct dma_buf *ion_dmabuf_alloc(struct ion_device *dev, size_t len,
					unsigned int heap_id_mask,
					unsigned int flags);
extern int ion_free(struct ion_buffer *buffer);


#endif /* _ION_PRIVATE_H */
#endif /* _ION_PRIVATE_H */
Loading