Commit c30707be authored by Rebecca Schultz Zavin's avatar Rebecca Schultz Zavin Committed by Greg Kroah-Hartman

gpu: ion: Add ION Memory Manager

Signed-off-by: default avatarRebecca Schultz Zavin <rebecca@android.com>
[jstultz: Squished in Colin Cross' move to staging change,
also disables ION from the build, as it won't compile till
the end of the patchset]
Signed-off-by: default avatarJohn Stultz <john.stultz@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 530376bf
......@@ -100,6 +100,8 @@ config SW_SYNC_USER
*WARNING* improper use of this can result in deadlocking kernel
drivers from userspace.
source "drivers/staging/android/ion/Kconfig"
endif # if ANDROID
endmenu
ccflags-y += -I$(src) # needed for trace events
# ION doesn't build just yet, so disable it from the build
#obj-y += ion/
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj-$(CONFIG_ASHMEM) += ashmem.o
obj-$(CONFIG_ANDROID_LOGGER) += logger.o
......
menuconfig ION
tristate "Ion Memory Manager"
select GENERIC_ALLOCATOR
help
Chose this option to enable the ION Memory Manager.
config ION_TEGRA
tristate "Ion for Tegra"
depends on ARCH_TEGRA && ION
help
Choose this option if you wish to use ion on an nVidia Tegra.
obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o
obj-$(CONFIG_ION_TEGRA) += tegra/
This diff is collapsed.
This diff is collapsed.
/*
* drivers/staging/android/ion/ion_carveout_heap.c
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/genalloc.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "ion.h"
#include "ion_priv.h"
#include <asm/mach/map.h>
struct ion_carveout_heap {
struct ion_heap heap;
struct gen_pool *pool;
ion_phys_addr_t base;
};
ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
unsigned long size,
unsigned long align)
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
unsigned long offset = gen_pool_alloc(carveout_heap->pool, size);
if (!offset)
return ION_CARVEOUT_ALLOCATE_FAIL;
return offset;
}
void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
unsigned long size)
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
if (addr == ION_CARVEOUT_ALLOCATE_FAIL)
return;
gen_pool_free(carveout_heap->pool, addr, size);
}
static int ion_carveout_heap_phys(struct ion_heap *heap,
struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len)
{
*addr = buffer->priv_phys;
*len = buffer->size;
return 0;
}
static int ion_carveout_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long size, unsigned long align,
unsigned long flags)
{
buffer->priv_phys = ion_carveout_allocate(heap, size, align);
return buffer->priv_phys == ION_CARVEOUT_ALLOCATE_FAIL ? -ENOMEM : 0;
}
static void ion_carveout_heap_free(struct ion_buffer *buffer)
{
struct ion_heap *heap = buffer->heap;
ion_carveout_free(heap, buffer->priv_phys, buffer->size);
buffer->priv_phys = ION_CARVEOUT_ALLOCATE_FAIL;
}
struct scatterlist *ion_carveout_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return ERR_PTR(-EINVAL);
}
void ion_carveout_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return;
}
void *ion_carveout_heap_map_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return __arch_ioremap(buffer->priv_phys, buffer->size,
MT_MEMORY_NONCACHED);
}
void ion_carveout_heap_unmap_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
__arch_iounmap(buffer->vaddr);
buffer->vaddr = NULL;
return;
}
int ion_carveout_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
struct vm_area_struct *vma)
{
return remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
buffer->size,
pgprot_noncached(vma->vm_page_prot));
}
static struct ion_heap_ops carveout_heap_ops = {
.allocate = ion_carveout_heap_allocate,
.free = ion_carveout_heap_free,
.phys = ion_carveout_heap_phys,
.map_user = ion_carveout_heap_map_user,
.map_kernel = ion_carveout_heap_map_kernel,
.unmap_kernel = ion_carveout_heap_unmap_kernel,
};
struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_carveout_heap *carveout_heap;
carveout_heap = kzalloc(sizeof(struct ion_carveout_heap), GFP_KERNEL);
if (!carveout_heap)
return ERR_PTR(-ENOMEM);
carveout_heap->pool = gen_pool_create(12, -1);
if (!carveout_heap->pool) {
kfree(carveout_heap);
return ERR_PTR(-ENOMEM);
}
carveout_heap->base = heap_data->base;
gen_pool_add(carveout_heap->pool, carveout_heap->base, heap_data->size,
-1);
carveout_heap->heap.ops = &carveout_heap_ops;
carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
return &carveout_heap->heap;
}
void ion_carveout_heap_destroy(struct ion_heap *heap)
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
gen_pool_destroy(carveout_heap->pool);
kfree(carveout_heap);
carveout_heap = NULL;
}
/*
* drivers/staging/android/ion/ion_heap.c
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/err.h>
#include "ion.h"
#include "ion_priv.h"
struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_heap *heap = NULL;
switch (heap_data->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:
heap = ion_system_contig_heap_create(heap_data);
break;
case ION_HEAP_TYPE_SYSTEM:
heap = ion_system_heap_create(heap_data);
break;
case ION_HEAP_TYPE_CARVEOUT:
heap = ion_carveout_heap_create(heap_data);
break;
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap_data->type);
return ERR_PTR(-EINVAL);
}
if (IS_ERR_OR_NULL(heap)) {
pr_err("%s: error creating heap %s type %d base %lu size %u\n",
__func__, heap_data->name, heap_data->type,
heap_data->base, heap_data->size);
return ERR_PTR(-EINVAL);
}
heap->name = heap_data->name;
heap->id = heap_data->id;
return heap;
}
void ion_heap_destroy(struct ion_heap *heap)
{
if (!heap)
return;
switch (heap->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:
ion_system_contig_heap_destroy(heap);
break;
case ION_HEAP_TYPE_SYSTEM:
ion_system_heap_destroy(heap);
break;
case ION_HEAP_TYPE_CARVEOUT:
ion_carveout_heap_destroy(heap);
break;
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap->type);
}
}
/*
* drivers/staging/android/ion/ion_priv.h
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#ifndef _ION_PRIV_H
#define _ION_PRIV_H
#include <linux/kref.h>
#include <linux/mm_types.h>
#include <linux/mutex.h>
#include <linux/rbtree.h>
#include "ion.h"
struct ion_mapping;
struct ion_dma_mapping {
struct kref ref;
struct scatterlist *sglist;
};
struct ion_kernel_mapping {
struct kref ref;
void *vaddr;
};
struct ion_buffer *ion_handle_buffer(struct ion_handle *handle);
/**
* struct ion_buffer - metadata for a particular buffer
* @ref: refernce count
* @node: node in the ion_device buffers tree
* @dev: back pointer to the ion_device
* @heap: back pointer to the heap the buffer came from
* @flags: buffer specific flags
* @size: size of the buffer
* @priv_virt: private data to the buffer representable as
* a void *
* @priv_phys: private data to the buffer representable as
* an ion_phys_addr_t (and someday a phys_addr_t)
* @lock: protects the buffers cnt fields
* @kmap_cnt: number of times the buffer is mapped to the kernel
* @vaddr: the kenrel mapping if kmap_cnt is not zero
* @dmap_cnt: number of times the buffer is mapped for dma
* @sglist: the scatterlist for the buffer is dmap_cnt is not zero
*/
struct ion_buffer {
struct kref ref;
struct rb_node node;
struct ion_device *dev;
struct ion_heap *heap;
unsigned long flags;
size_t size;
union {
void *priv_virt;
ion_phys_addr_t priv_phys;
};
struct mutex lock;
int kmap_cnt;
void *vaddr;
int dmap_cnt;
struct scatterlist *sglist;
};
/**
* struct ion_heap_ops - ops to operate on a given heap
* @allocate: allocate memory
* @free: free memory
* @phys get physical address of a buffer (only define on
* physically contiguous heaps)
* @map_dma map the memory for dma to a scatterlist
* @unmap_dma unmap the memory for dma
* @map_kernel map memory to the kernel
* @unmap_kernel unmap memory to the kernel
* @map_user map memory to userspace
*/
struct ion_heap_ops {
int (*allocate) (struct ion_heap *heap,
struct ion_buffer *buffer, unsigned long len,
unsigned long align, unsigned long flags);
void (*free) (struct ion_buffer *buffer);
int (*phys) (struct ion_heap *heap, struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len);
struct scatterlist *(*map_dma) (struct ion_heap *heap,
struct ion_buffer *buffer);
void (*unmap_dma) (struct ion_heap *heap, struct ion_buffer *buffer);
void * (*map_kernel) (struct ion_heap *heap, struct ion_buffer *buffer);
void (*unmap_kernel) (struct ion_heap *heap, struct ion_buffer *buffer);
int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer,
struct vm_area_struct *vma);
};
/**
* struct ion_heap - represents a heap in the system
* @node: rb node to put the heap on the device's tree of heaps
* @dev: back pointer to the ion_device
* @type: type of heap
* @ops: ops struct as above
* @id: id of heap, also indicates priority of this heap when
* allocating. These are specified by platform data and
* MUST be unique
* @name: used for debugging
*
* Represents a pool of memory from which buffers can be made. In some
* systems the only heap is regular system memory allocated via vmalloc.
* On others, some blocks might require large physically contiguous buffers
* that are allocated from a specially reserved heap.
*/
struct ion_heap {
struct rb_node node;
struct ion_device *dev;
enum ion_heap_type type;
struct ion_heap_ops *ops;
int id;
const char *name;
};
/**
* ion_device_create - allocates and returns an ion device
* @custom_ioctl: arch specific ioctl function if applicable
*
* returns a valid device or -PTR_ERR
*/
struct ion_device *ion_device_create(long (*custom_ioctl)
(struct ion_client *client,
unsigned int cmd,
unsigned long arg));
/**
* ion_device_destroy - free and device and it's resource
* @dev: the device
*/
void ion_device_destroy(struct ion_device *dev);
/**
* ion_device_add_heap - adds a heap to the ion device
* @dev: the device
* @heap: the heap to add
*/
void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap);
/**
* functions for creating and destroying the built in ion heaps.
* architectures can add their own custom architecture specific
* heaps as appropriate.
*/
struct ion_heap *ion_heap_create(struct ion_platform_heap *);
void ion_heap_destroy(struct ion_heap *);
struct ion_heap *ion_system_heap_create(struct ion_platform_heap *);
void ion_system_heap_destroy(struct ion_heap *);
struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *);
void ion_system_contig_heap_destroy(struct ion_heap *);
struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *);
void ion_carveout_heap_destroy(struct ion_heap *);
/**
* kernel api to allocate/free from carveout -- used when carveout is
* used to back an architecture specific custom heap
*/
ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, unsigned long size,
unsigned long align);
void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
unsigned long size);
/**
* The carveout heap returns physical addresses, since 0 may be a valid
* physical address, this is used to indicate allocation failed
*/
#define ION_CARVEOUT_ALLOCATE_FAIL -1
#endif /* _ION_PRIV_H */
/*
* drivers/staging/android/ion/ion_system_heap.c
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/err.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "ion.h"
#include "ion_priv.h"
static int ion_system_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long size, unsigned long align,
unsigned long flags)
{
buffer->priv_virt = vmalloc_user(size);
if (!buffer->priv_virt)
return -ENOMEM;
return 0;
}
void ion_system_heap_free(struct ion_buffer *buffer)
{
vfree(buffer->priv_virt);
}
struct scatterlist *ion_system_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
struct scatterlist *sglist;
struct page *page;
int i;
int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
void *vaddr = buffer->priv_virt;
sglist = vmalloc(npages * sizeof(struct scatterlist));
if (!sglist)
return ERR_PTR(-ENOMEM);
memset(sglist, 0, npages * sizeof(struct scatterlist));
sg_init_table(sglist, npages);
for (i = 0; i < npages; i++) {
page = vmalloc_to_page(vaddr);
if (!page)
goto end;
sg_set_page(&sglist[i], page, PAGE_SIZE, 0);
vaddr += PAGE_SIZE;
}
/* XXX do cache maintenance for dma? */
return sglist;
end:
vfree(sglist);
return NULL;
}
void ion_system_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
/* XXX undo cache maintenance for dma? */
if (buffer->sglist)
vfree(buffer->sglist);
}
void *ion_system_heap_map_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return buffer->priv_virt;
}
void ion_system_heap_unmap_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
}
int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
struct vm_area_struct *vma)
{
return remap_vmalloc_range(vma, buffer->priv_virt, vma->vm_pgoff);
}
static struct ion_heap_ops vmalloc_ops = {
.allocate = ion_system_heap_allocate,
.free = ion_system_heap_free,
.map_dma = ion_system_heap_map_dma,
.unmap_dma = ion_system_heap_unmap_dma,
.map_kernel = ion_system_heap_map_kernel,
.unmap_kernel = ion_system_heap_unmap_kernel,
.map_user = ion_system_heap_map_user,
};
struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
{
struct ion_heap *heap;
heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
if (!heap)
return ERR_PTR(-ENOMEM);
heap->ops = &vmalloc_ops;
heap->type = ION_HEAP_TYPE_SYSTEM;
return heap;
}
void ion_system_heap_destroy(struct ion_heap *heap)
{
kfree(heap);
}
static int ion_system_contig_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long len,
unsigned long align,
unsigned long flags)
{
buffer->priv_virt = kzalloc(len, GFP_KERNEL);
if (!buffer->priv_virt)
return -ENOMEM;
return 0;
}
void ion_system_contig_heap_free(struct ion_buffer *buffer)
{
kfree(buffer->priv_virt);
}
static int ion_system_contig_heap_phys(struct ion_heap *heap,
struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len)
{
*addr = virt_to_phys(buffer->priv_virt);
*len = buffer->size;
return 0;
}
struct scatterlist *ion_system_contig_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
struct scatterlist *sglist;
sglist = vmalloc(sizeof(struct scatterlist));
if (!sglist)
return ERR_PTR(-ENOMEM);
sg_init_table(sglist, 1);
sg_set_page(sglist, virt_to_page(buffer->priv_virt), buffer->size, 0);
return sglist;
}
int ion_system_contig_heap_map_user(struct ion_heap *heap,
struct ion_buffer *buffer,
struct vm_area_struct *vma)
{
unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt));
return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
static struct ion_heap_ops kmalloc_ops = {
.allocate = ion_system_contig_heap_allocate,
.free = ion_system_contig_heap_free,
.phys = ion_system_contig_heap_phys,
.map_dma = ion_system_contig_heap_map_dma,
.unmap_dma = ion_system_heap_unmap_dma,
.map_kernel = ion_system_heap_map_kernel,
.unmap_kernel = ion_system_heap_unmap_kernel,
.map_user = ion_system_contig_heap_map_user,
};
struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused)
{
struct ion_heap *heap;
heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
if (!heap)
return ERR_PTR(-ENOMEM);
heap->ops = &kmalloc_ops;
heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG;
return heap;
}
void ion_system_contig_heap_destroy(struct ion_heap *heap)
{
kfree(heap);
}
/*
* drivers/staging/android/ion/ion_system_mapper.c
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/err.h>
#include <linux/memory.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "ion.h"
#include "ion_priv.h"
/*
* This mapper is valid for any heap that allocates memory that already has
* a kernel mapping, this includes vmalloc'd memory, kmalloc'd memory,
* pages obtained via io_remap, etc.
*/
static void *ion_kernel_mapper_map(struct ion_mapper *mapper,
struct ion_buffer *buffer,
struct ion_mapping **mapping)
{
if (!((1 << buffer->heap->type) & mapper->heap_mask)) {
pr_err("%s: attempting to map an unsupported heap\n", __func__);
return ERR_PTR(-EINVAL);
}
/* XXX REVISIT ME!!! */
*((unsigned long *)mapping) = (unsigned long)buffer->priv;
return buffer->priv;
}
static void ion_kernel_mapper_unmap(struct ion_mapper *mapper,
struct ion_buffer *buffer,
struct ion_mapping *mapping)
{
if (!((1 << buffer->heap->type) & mapper->heap_mask))
pr_err("%s: attempting to unmap an unsupported heap\n",
__func__);
}
static void *ion_kernel_mapper_map_kernel(struct ion_mapper *mapper,
struct ion_buffer *buffer,
struct ion_mapping *mapping)
{
if (!((1 << buffer->heap->type) & mapper->heap_mask)) {
pr_err("%s: attempting to unmap an unsupported heap\n",
__func__);
return ERR_PTR(-EINVAL);
}
return buffer->priv;
}
static int ion_kernel_mapper_map_user(struct ion_mapper *mapper,
struct ion_buffer *buffer,
struct vm_area_struct *vma,
struct ion_mapping *mapping)
{
int ret;
switch (buffer->heap->type) {
case ION_HEAP_KMALLOC:
{
unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv));
ret = remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
break;
}
case ION_HEAP_VMALLOC:
ret = remap_vmalloc_range(vma, buffer->priv, vma->vm_pgoff);
break;
default:
pr_err("%s: attempting to map unsupported heap to userspace\n",
__func__);
return -EINVAL;
}
return ret;
}
static struct ion_mapper_ops ops = {
.map = ion_kernel_mapper_map,
.map_kernel = ion_kernel_mapper_map_kernel,
.map_user = ion_kernel_mapper_map_user,
.unmap = ion_kernel_mapper_unmap,
};
struct ion_mapper *ion_system_mapper_create(void)
{
struct ion_mapper *mapper;
mapper = kzalloc(sizeof(struct ion_mapper), GFP_KERNEL);
if (!mapper)
return ERR_PTR(-ENOMEM);
mapper->type = ION_SYSTEM_MAPPER;
mapper->ops = &ops;
mapper->heap_mask = (1 << ION_HEAP_VMALLOC) | (1 << ION_HEAP_KMALLOC);
return mapper;
}
void ion_system_mapper_destroy(struct ion_mapper *mapper)
{
kfree(mapper);
}
/*
* drivers/gpu/tegra/tegra_ion.c
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "../ion.h"
#include "../ion_priv.h"
struct ion_device *idev;
struct ion_mapper *tegra_user_mapper;
int num_heaps;
struct ion_heap **heaps;
int tegra_ion_probe(struct platform_device *pdev)
{
struct ion_platform_data *pdata = pdev->dev.platform_data;
int err;
int i;
num_heaps = pdata->nr;
heaps = kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL);
idev = ion_device_create(NULL);
if (IS_ERR_OR_NULL(idev)) {
kfree(heaps);
return PTR_ERR(idev);
}
/* create the heaps as specified in the board file */
for (i = 0; i < num_heaps; i++) {
struct ion_platform_heap *heap_data = &pdata->heaps[i];
heaps[i] = ion_heap_create(heap_data);
if (IS_ERR_OR_NULL(heaps[i])) {
err = PTR_ERR(heaps[i]);
goto err;
}
ion_device_add_heap(idev, heaps[i]);
}
platform_set_drvdata(pdev, idev);
return 0;
err:
for (i = 0; i < num_heaps; i++) {
if (heaps[i])
ion_heap_destroy(heaps[i]);
}
kfree(heaps);
return err;
}
int tegra_ion_remove(struct platform_device *pdev)
{
struct ion_device *idev = platform_get_drvdata(pdev);
int i;
ion_device_destroy(idev);
for (i = 0; i < num_heaps; i++)
ion_heap_destroy(heaps[i]);
kfree(heaps);
return 0;
}
static struct platform_driver ion_driver = {
.probe = tegra_ion_probe,
.remove = tegra_ion_remove,
.driver = { .name = "ion-tegra" }
};
static int __init ion_init(void)
{
return platform_driver_register(&ion_driver);
}
static void __exit ion_exit(void)
{
platform_driver_unregister(&ion_driver);
}
module_init(ion_init);
module_exit(ion_exit);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment