All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sumit Semwal <sumit.semwal@linaro.org>
To: linux-kernel@vger.kernel.org
Cc: linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linaro-mm-sig@lists.linaro.org, linaro-kernel@lists.linaro.org,
	Benjamin Gaignard <benjamin.gaignard@linaro.org>,
	Sumit Semwal <sumit.semwal@linaro.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: [RFC 4/4] cenalloc: a sample allocator for contiguous page allocation
Date: Sat, 11 Oct 2014 01:37:58 +0530	[thread overview]
Message-ID: <1412971678-4457-5-git-send-email-sumit.semwal@linaro.org> (raw)
In-Reply-To: <1412971678-4457-1-git-send-email-sumit.semwal@linaro.org>

From: Benjamin Gaignard <benjamin.gaignard@linaro.org>

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
Cc: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-media@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: linaro-mm-sig@lists.linaro.org
---
 drivers/cenalloc/Makefile                 |   2 +-
 drivers/cenalloc/cenalloc_system_contig.c | 225 ++++++++++++++++++++++++++++++
 2 files changed, 226 insertions(+), 1 deletion(-)
 create mode 100644 drivers/cenalloc/cenalloc_system_contig.c

diff --git a/drivers/cenalloc/Makefile b/drivers/cenalloc/Makefile
index d36b531..2f69b61 100644
--- a/drivers/cenalloc/Makefile
+++ b/drivers/cenalloc/Makefile
@@ -1,3 +1,3 @@
 # Makefile for the cenalloc helper
 
-obj-y				+= cenalloc.o
+obj-y				+= cenalloc.o cenalloc_system_contig.o
diff --git a/drivers/cenalloc/cenalloc_system_contig.c b/drivers/cenalloc/cenalloc_system_contig.c
new file mode 100644
index 0000000..ecf0c03
--- /dev/null
+++ b/drivers/cenalloc/cenalloc_system_contig.c
@@ -0,0 +1,225 @@
+/*
+ * central allocator using kmalloc
+ *
+ * Copyright(C) 2014 Linaro Limited. All rights reserved.
+ * Author: Benjamin Gaignard <benjamin.gaignard@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <asm/page.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "cenalloc_priv.h"
+
+static gfp_t low_order_gfp_flags  = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN);
+
+void cenalloc_pages_sync_for_device(struct device *dev, struct page *page,
+		size_t size, enum dma_data_direction dir)
+{
+	struct scatterlist sg;
+
+	sg_init_table(&sg, 1);
+	sg_set_page(&sg, page, size, 0);
+	/*
+	 * This is not correct - sg_dma_address needs a dma_addr_t that is valid
+	 * for the the targeted device, but this works on the currently targeted
+	 * hardware.
+	 */
+	sg_dma_address(&sg) = page_to_phys(page);
+	dma_sync_sg_for_device(dev, &sg, 1, dir);
+}
+
+static int cenalloc_system_contig_allocate(struct cenalloc_allocator *allocator,
+			struct cenalloc_buffer *buffer, unsigned long len,
+			unsigned long align, unsigned long flags)
+{
+	int order = get_order(len);
+		struct page *page;
+	struct sg_table *table;
+	unsigned long i;
+	int ret;
+
+	if (align > (PAGE_SIZE << order))
+		return -EINVAL;
+
+	page = alloc_pages(low_order_gfp_flags, order);
+	if (!page)
+		return -ENOMEM;
+
+	split_page(page, order);
+
+	len = PAGE_ALIGN(len);
+	for (i = len >> PAGE_SHIFT; i < (1 << order); i++)
+		__free_page(page + i);
+
+	table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!table) {
+		ret = -ENOMEM;
+		goto free_pages;
+	}
+
+	ret = sg_alloc_table(table, 1, GFP_KERNEL);
+	if (ret)
+		goto free_table;
+
+	sg_set_page(table->sgl, page, len, 0);
+
+	buffer->sg_table = table;
+
+	cenalloc_pages_sync_for_device(NULL, page, len, DMA_BIDIRECTIONAL);
+
+	return 0;
+
+free_table:
+	kfree(table);
+free_pages:
+	for (i = 0; i < len >> PAGE_SHIFT; i++)
+		__free_page(page + i);
+
+	return ret;
+
+}
+
+static void cenalloc_system_contig_free(struct cenalloc_buffer *buffer)
+{
+	struct sg_table *table = buffer->sg_table;
+	struct page *page = sg_page(table->sgl);
+	unsigned long pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT;
+	unsigned long i;
+
+	for (i = 0; i < pages; i++)
+		__free_page(page + i);
+	sg_free_table(table);
+	kfree(table);
+}
+
+static struct sg_table *cenalloc_system_contig_map_dma
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer)
+{
+	return buffer->sg_table;
+}
+
+static void cenalloc_system_contig_unmap_dma
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer)
+{
+
+}
+
+static void *cenalloc_system_contig_map_kernel
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer)
+{
+	struct scatterlist *sg;
+	int i, j;
+	void *vaddr;
+	pgprot_t pgprot;
+	struct sg_table *table = buffer->sg_table;
+	int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+	struct page **pages = vmalloc(sizeof(struct page *) * npages);
+	struct page **tmp = pages;
+
+	if (!pages)
+		return NULL;
+
+	pgprot = pgprot_writecombine(PAGE_KERNEL);
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE;
+		struct page *page = sg_page(sg);
+
+		BUG_ON(i >= npages);
+		for (j = 0; j < npages_this_entry; j++)
+			*(tmp++) = page++;
+	}
+	vaddr = vmap(pages, npages, VM_MAP, pgprot);
+	vfree(pages);
+
+	if (vaddr == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	return vaddr;
+}
+
+static void cenalloc_system_contig_unmap_kernel
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer)
+{
+	vunmap(buffer->vaddr);
+}
+
+static int cenalloc_system_contig_map_user
+	(struct cenalloc_allocator *mapper, struct cenalloc_buffer *buffer,
+			struct vm_area_struct *vma)
+{
+	struct sg_table *table = buffer->sg_table;
+	unsigned long addr = vma->vm_start;
+	unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+	struct scatterlist *sg;
+	int i;
+	int ret;
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		struct page *page = sg_page(sg);
+		unsigned long remainder = vma->vm_end - addr;
+		unsigned long len = sg->length;
+
+		if (offset >= sg->length) {
+			offset -= sg->length;
+			continue;
+		} else if (offset) {
+			page += offset / PAGE_SIZE;
+			len = sg->length - offset;
+			offset = 0;
+		}
+		len = min(len, remainder);
+		ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
+				vma->vm_page_prot);
+		if (ret)
+			return ret;
+		addr += len;
+		if (addr >= vma->vm_end)
+			return 0;
+	}
+	return 0;
+}
+
+static void cenalloc_system_contig_sync_for_device
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer,
+		struct device *dev, enum dma_data_direction dir)
+{
+	/* TODO */
+}
+
+static struct cenalloc_allocator_ops system_contig_ops = {
+	.allocate = cenalloc_system_contig_allocate,
+	.free = cenalloc_system_contig_free,
+	.map_dma = cenalloc_system_contig_map_dma,
+	.unmap_dma = cenalloc_system_contig_unmap_dma,
+	.map_kernel = cenalloc_system_contig_map_kernel,
+	.unmap_kernel = cenalloc_system_contig_unmap_kernel,
+	.map_user = cenalloc_system_contig_map_user,
+	.sync_for_device = cenalloc_system_contig_sync_for_device,
+};
+
+struct cenalloc_allocator system_contig = {
+	.ops = &system_contig_ops,
+	.type = CENALLOC_ALLOCATOR_SYSTEM,
+	.id = CENALLOC_ALLOCATOR_SYSTEM,
+	.name = "system contiguous memory allocator",
+};
-- 
1.9.1


WARNING: multiple messages have this Message-ID (diff)
From: Sumit Semwal <sumit.semwal@linaro.org>
To: linux-kernel@vger.kernel.org
Cc: linaro-kernel@lists.linaro.org,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org,
	Benjamin Gaignard <benjamin.gaignard@linaro.org>,
	linux-media@vger.kernel.org
Subject: [RFC 4/4] cenalloc: a sample allocator for contiguous page allocation
Date: Sat, 11 Oct 2014 01:37:58 +0530	[thread overview]
Message-ID: <1412971678-4457-5-git-send-email-sumit.semwal@linaro.org> (raw)
In-Reply-To: <1412971678-4457-1-git-send-email-sumit.semwal@linaro.org>

From: Benjamin Gaignard <benjamin.gaignard@linaro.org>

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
Cc: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-media@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: linaro-mm-sig@lists.linaro.org
---
 drivers/cenalloc/Makefile                 |   2 +-
 drivers/cenalloc/cenalloc_system_contig.c | 225 ++++++++++++++++++++++++++++++
 2 files changed, 226 insertions(+), 1 deletion(-)
 create mode 100644 drivers/cenalloc/cenalloc_system_contig.c

diff --git a/drivers/cenalloc/Makefile b/drivers/cenalloc/Makefile
index d36b531..2f69b61 100644
--- a/drivers/cenalloc/Makefile
+++ b/drivers/cenalloc/Makefile
@@ -1,3 +1,3 @@
 # Makefile for the cenalloc helper
 
-obj-y				+= cenalloc.o
+obj-y				+= cenalloc.o cenalloc_system_contig.o
diff --git a/drivers/cenalloc/cenalloc_system_contig.c b/drivers/cenalloc/cenalloc_system_contig.c
new file mode 100644
index 0000000..ecf0c03
--- /dev/null
+++ b/drivers/cenalloc/cenalloc_system_contig.c
@@ -0,0 +1,225 @@
+/*
+ * central allocator using kmalloc
+ *
+ * Copyright(C) 2014 Linaro Limited. All rights reserved.
+ * Author: Benjamin Gaignard <benjamin.gaignard@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <asm/page.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "cenalloc_priv.h"
+
+static gfp_t low_order_gfp_flags  = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN);
+
+void cenalloc_pages_sync_for_device(struct device *dev, struct page *page,
+		size_t size, enum dma_data_direction dir)
+{
+	struct scatterlist sg;
+
+	sg_init_table(&sg, 1);
+	sg_set_page(&sg, page, size, 0);
+	/*
+	 * This is not correct - sg_dma_address needs a dma_addr_t that is valid
+	 * for the the targeted device, but this works on the currently targeted
+	 * hardware.
+	 */
+	sg_dma_address(&sg) = page_to_phys(page);
+	dma_sync_sg_for_device(dev, &sg, 1, dir);
+}
+
+static int cenalloc_system_contig_allocate(struct cenalloc_allocator *allocator,
+			struct cenalloc_buffer *buffer, unsigned long len,
+			unsigned long align, unsigned long flags)
+{
+	int order = get_order(len);
+		struct page *page;
+	struct sg_table *table;
+	unsigned long i;
+	int ret;
+
+	if (align > (PAGE_SIZE << order))
+		return -EINVAL;
+
+	page = alloc_pages(low_order_gfp_flags, order);
+	if (!page)
+		return -ENOMEM;
+
+	split_page(page, order);
+
+	len = PAGE_ALIGN(len);
+	for (i = len >> PAGE_SHIFT; i < (1 << order); i++)
+		__free_page(page + i);
+
+	table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!table) {
+		ret = -ENOMEM;
+		goto free_pages;
+	}
+
+	ret = sg_alloc_table(table, 1, GFP_KERNEL);
+	if (ret)
+		goto free_table;
+
+	sg_set_page(table->sgl, page, len, 0);
+
+	buffer->sg_table = table;
+
+	cenalloc_pages_sync_for_device(NULL, page, len, DMA_BIDIRECTIONAL);
+
+	return 0;
+
+free_table:
+	kfree(table);
+free_pages:
+	for (i = 0; i < len >> PAGE_SHIFT; i++)
+		__free_page(page + i);
+
+	return ret;
+
+}
+
+static void cenalloc_system_contig_free(struct cenalloc_buffer *buffer)
+{
+	struct sg_table *table = buffer->sg_table;
+	struct page *page = sg_page(table->sgl);
+	unsigned long pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT;
+	unsigned long i;
+
+	for (i = 0; i < pages; i++)
+		__free_page(page + i);
+	sg_free_table(table);
+	kfree(table);
+}
+
+static struct sg_table *cenalloc_system_contig_map_dma
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer)
+{
+	return buffer->sg_table;
+}
+
+static void cenalloc_system_contig_unmap_dma
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer)
+{
+
+}
+
+static void *cenalloc_system_contig_map_kernel
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer)
+{
+	struct scatterlist *sg;
+	int i, j;
+	void *vaddr;
+	pgprot_t pgprot;
+	struct sg_table *table = buffer->sg_table;
+	int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+	struct page **pages = vmalloc(sizeof(struct page *) * npages);
+	struct page **tmp = pages;
+
+	if (!pages)
+		return NULL;
+
+	pgprot = pgprot_writecombine(PAGE_KERNEL);
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE;
+		struct page *page = sg_page(sg);
+
+		BUG_ON(i >= npages);
+		for (j = 0; j < npages_this_entry; j++)
+			*(tmp++) = page++;
+	}
+	vaddr = vmap(pages, npages, VM_MAP, pgprot);
+	vfree(pages);
+
+	if (vaddr == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	return vaddr;
+}
+
+static void cenalloc_system_contig_unmap_kernel
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer)
+{
+	vunmap(buffer->vaddr);
+}
+
+static int cenalloc_system_contig_map_user
+	(struct cenalloc_allocator *mapper, struct cenalloc_buffer *buffer,
+			struct vm_area_struct *vma)
+{
+	struct sg_table *table = buffer->sg_table;
+	unsigned long addr = vma->vm_start;
+	unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+	struct scatterlist *sg;
+	int i;
+	int ret;
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		struct page *page = sg_page(sg);
+		unsigned long remainder = vma->vm_end - addr;
+		unsigned long len = sg->length;
+
+		if (offset >= sg->length) {
+			offset -= sg->length;
+			continue;
+		} else if (offset) {
+			page += offset / PAGE_SIZE;
+			len = sg->length - offset;
+			offset = 0;
+		}
+		len = min(len, remainder);
+		ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
+				vma->vm_page_prot);
+		if (ret)
+			return ret;
+		addr += len;
+		if (addr >= vma->vm_end)
+			return 0;
+	}
+	return 0;
+}
+
+static void cenalloc_system_contig_sync_for_device
+	(struct cenalloc_allocator *allocator, struct cenalloc_buffer *buffer,
+		struct device *dev, enum dma_data_direction dir)
+{
+	/* TODO */
+}
+
+static struct cenalloc_allocator_ops system_contig_ops = {
+	.allocate = cenalloc_system_contig_allocate,
+	.free = cenalloc_system_contig_free,
+	.map_dma = cenalloc_system_contig_map_dma,
+	.unmap_dma = cenalloc_system_contig_unmap_dma,
+	.map_kernel = cenalloc_system_contig_map_kernel,
+	.unmap_kernel = cenalloc_system_contig_unmap_kernel,
+	.map_user = cenalloc_system_contig_map_user,
+	.sync_for_device = cenalloc_system_contig_sync_for_device,
+};
+
+struct cenalloc_allocator system_contig = {
+	.ops = &system_contig_ops,
+	.type = CENALLOC_ALLOCATOR_SYSTEM,
+	.id = CENALLOC_ALLOCATOR_SYSTEM,
+	.name = "system contiguous memory allocator",
+};
-- 
1.9.1

  parent reply	other threads:[~2014-10-10 20:09 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-10 20:07 [RFC 0/4] dma-buf Constraints-Enabled Allocation helpers Sumit Semwal
2014-10-10 20:07 ` Sumit Semwal
2014-10-10 20:07 ` [RFC 1/4] dma-buf: Add constraints sharing information Sumit Semwal
2014-10-10 20:07   ` Sumit Semwal
2014-10-11 18:55   ` Daniel Vetter
2014-10-11 18:55     ` Daniel Vetter
2014-10-13  8:14     ` [Linaro-mm-sig] " Laura Abbott
2014-10-13  9:32       ` Daniel Vetter
2014-10-13  9:32         ` Daniel Vetter
2014-12-10 13:31     ` Sumit Semwal
2014-12-10 13:31       ` Sumit Semwal
2014-12-10 13:47       ` Daniel Vetter
2014-12-10 13:47         ` Daniel Vetter
2015-01-08 14:14         ` [Linaro-mm-sig] " Benjamin Gaignard
2014-10-10 20:07 ` [RFC 2/4] cenalloc: Constraint-Enabled Allocation helpers for dma-buf Sumit Semwal
2014-10-10 20:07   ` Sumit Semwal
2014-10-10 23:09   ` Greg Kroah-Hartman
2014-10-10 23:09     ` Greg Kroah-Hartman
2014-10-11 18:40     ` Daniel Vetter
2014-10-11 18:40       ` Daniel Vetter
2014-10-14 14:03       ` Sumit Semwal
2014-10-14 14:03         ` Sumit Semwal
2014-10-13  8:35   ` [Linaro-mm-sig] " Laura Abbott
2014-10-14 14:11     ` Sumit Semwal
2014-10-10 20:07 ` [RFC 3/4] cenalloc: Build files for constraint-enabled allocation helpers Sumit Semwal
2014-10-10 20:07 ` Sumit Semwal [this message]
2014-10-10 20:07   ` [RFC 4/4] cenalloc: a sample allocator for contiguous page allocation Sumit Semwal
2014-10-13  8:12 ` [Linaro-mm-sig] [RFC 0/4] dma-buf Constraints-Enabled Allocation helpers Laura Abbott
2014-10-14 14:00   ` Sumit Semwal
2014-10-14 14:00     ` Sumit Semwal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1412971678-4457-5-git-send-email-sumit.semwal@linaro.org \
    --to=sumit.semwal@linaro.org \
    --cc=benjamin.gaignard@linaro.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linaro-kernel@lists.linaro.org \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.