blob: ce854565b5634a91732c8624358cd256b6f8509a [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* ION Memory Allocator system contig heap exporter
*
* Copyright (C) 2019 Google, Inc.
*/
#include <asm/page.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/ion.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
static int ion_system_contig_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long len,
unsigned long flags)
{
int order = get_order(len);
struct page *page;
struct sg_table *table;
unsigned long i;
int ret;
page = alloc_pages(GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN, 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(*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;
ion_buffer_prep_noncached(buffer);
return 0;
free_table:
kfree(table);
free_pages:
for (i = 0; i < len >> PAGE_SHIFT; i++)
__free_page(page + i);
return ret;
}
static void ion_system_contig_heap_free(struct ion_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 ion_heap_ops kmalloc_ops = {
.allocate = ion_system_contig_heap_allocate,
.free = ion_system_contig_heap_free,
};
static struct ion_heap contig_heap = {
.ops = &kmalloc_ops,
.type = ION_HEAP_TYPE_SYSTEM_CONTIG,
.name = "ion_system_contig_heap",
};
static int __init ion_system_contig_heap_init(void)
{
return ion_device_add_heap(&contig_heap);
}
static void __exit ion_system_contig_heap_exit(void)
{
ion_device_remove_heap(&contig_heap);
}
module_init(ion_system_contig_heap_init);
module_exit(ion_system_contig_heap_exit);
MODULE_LICENSE("GPL v2");