gpu: ion: Add ION Memory Manager
Signed-off-by: Rebecca 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: John Stultz <john.stultz@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
530376bfb7
Коммит
c30707be12
|
@ -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
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
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
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
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.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o
|
||||
obj-$(CONFIG_ION_TEGRA) += tegra/
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
* drivers/staging/android/ion/ion.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 _LINUX_ION_H
|
||||
#define _LINUX_ION_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct ion_handle;
|
||||
/**
|
||||
* enum ion_heap_types - list of all possible types of heaps
|
||||
* @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
|
||||
* @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
|
||||
* @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved
|
||||
* carveout heap, allocations are physically
|
||||
* contiguous
|
||||
* @ION_HEAP_END: helper for iterating over heaps
|
||||
*/
|
||||
enum ion_heap_type {
|
||||
ION_HEAP_TYPE_SYSTEM,
|
||||
ION_HEAP_TYPE_SYSTEM_CONTIG,
|
||||
ION_HEAP_TYPE_CARVEOUT,
|
||||
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
|
||||
are at the end of this enum */
|
||||
ION_NUM_HEAPS,
|
||||
};
|
||||
|
||||
#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM)
|
||||
#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
|
||||
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
struct ion_device;
|
||||
struct ion_heap;
|
||||
struct ion_mapper;
|
||||
struct ion_client;
|
||||
struct ion_buffer;
|
||||
|
||||
/* This should be removed some day when phys_addr_t's are fully
|
||||
plumbed in the kernel, and all instances of ion_phys_addr_t should
|
||||
be converted to phys_addr_t. For the time being many kernel interfaces
|
||||
do not accept phys_addr_t's that would have to */
|
||||
#define ion_phys_addr_t unsigned long
|
||||
|
||||
/**
|
||||
* struct ion_platform_heap - defines a heap in the given platform
|
||||
* @type: type of the heap from ion_heap_type enum
|
||||
* @id: unique identifier for heap. When allocating (lower numbers
|
||||
* will be allocated from first)
|
||||
* @name: used for debug purposes
|
||||
* @base: base address of heap in physical memory if applicable
|
||||
* @size: size of the heap in bytes if applicable
|
||||
*
|
||||
* Provided by the board file.
|
||||
*/
|
||||
struct ion_platform_heap {
|
||||
enum ion_heap_type type;
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
ion_phys_addr_t base;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ion_platform_data - array of platform heaps passed from board file
|
||||
* @nr: number of structures in the array
|
||||
* @heaps: array of platform_heap structions
|
||||
*
|
||||
* Provided by the board file in the form of platform data to a platform device.
|
||||
*/
|
||||
struct ion_platform_data {
|
||||
int nr;
|
||||
struct ion_platform_heap heaps[];
|
||||
};
|
||||
|
||||
/**
|
||||
* ion_client_create() - allocate a client and returns it
|
||||
* @dev: the global ion device
|
||||
* @heap_mask: mask of heaps this client can allocate from
|
||||
* @name: used for debugging
|
||||
*/
|
||||
struct ion_client *ion_client_create(struct ion_device *dev,
|
||||
unsigned int heap_mask, const char *name);
|
||||
|
||||
/**
|
||||
* ion_client_destroy() - free's a client and all it's handles
|
||||
* @client: the client
|
||||
*
|
||||
* Free the provided client and all it's resources including
|
||||
* any handles it is holding.
|
||||
*/
|
||||
void ion_client_destroy(struct ion_client *client);
|
||||
|
||||
/**
|
||||
* ion_alloc - allocate ion memory
|
||||
* @client: the client
|
||||
* @len: size of the allocation
|
||||
* @align: requested allocation alignment, lots of hardware blocks have
|
||||
* alignment requirements of some kind
|
||||
* @flags: mask of heaps to allocate from, if multiple bits are set
|
||||
* heaps will be tried in order from lowest to highest order bit
|
||||
*
|
||||
* Allocate memory in one of the heaps provided in heap mask and return
|
||||
* an opaque handle to it.
|
||||
*/
|
||||
struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
|
||||
size_t align, unsigned int flags);
|
||||
|
||||
/**
|
||||
* ion_free - free a handle
|
||||
* @client: the client
|
||||
* @handle: the handle to free
|
||||
*
|
||||
* Free the provided handle.
|
||||
*/
|
||||
void ion_free(struct ion_client *client, struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_phys - returns the physical address and len of a handle
|
||||
* @client: the client
|
||||
* @handle: the handle
|
||||
* @addr: a pointer to put the address in
|
||||
* @len: a pointer to put the length in
|
||||
*
|
||||
* This function queries the heap for a particular handle to get the
|
||||
* handle's physical address. It't output is only correct if
|
||||
* a heap returns physically contiguous memory -- in other cases
|
||||
* this api should not be implemented -- ion_map_dma should be used
|
||||
* instead. Returns -EINVAL if the handle is invalid. This has
|
||||
* no implications on the reference counting of the handle --
|
||||
* the returned value may not be valid if the caller is not
|
||||
* holding a reference.
|
||||
*/
|
||||
int ion_phys(struct ion_client *client, struct ion_handle *handle,
|
||||
ion_phys_addr_t *addr, size_t *len);
|
||||
|
||||
/**
|
||||
* ion_map_kernel - create mapping for the given handle
|
||||
* @client: the client
|
||||
* @handle: handle to map
|
||||
*
|
||||
* Map the given handle into the kernel and return a kernel address that
|
||||
* can be used to access this address.
|
||||
*/
|
||||
void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_unmap_kernel() - destroy a kernel mapping for a handle
|
||||
* @client: the client
|
||||
* @handle: handle to unmap
|
||||
*/
|
||||
void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_map_dma - create a dma mapping for a given handle
|
||||
* @client: the client
|
||||
* @handle: handle to map
|
||||
*
|
||||
* Return an sglist describing the given handle
|
||||
*/
|
||||
struct scatterlist *ion_map_dma(struct ion_client *client,
|
||||
struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_unmap_dma() - destroy a dma mapping for a handle
|
||||
* @client: the client
|
||||
* @handle: handle to unmap
|
||||
*/
|
||||
void ion_unmap_dma(struct ion_client *client, struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_share() - given a handle, obtain a buffer to pass to other clients
|
||||
* @client: the client
|
||||
* @handle: the handle to share
|
||||
*
|
||||
* Given a handle, return a buffer, which exists in a global name
|
||||
* space, and can be passed to other clients. Should be passed into ion_import
|
||||
* to obtain a new handle for this buffer.
|
||||
*
|
||||
* NOTE: This function does do not an extra reference. The burden is on the
|
||||
* caller to make sure the buffer doesn't go away while it's being passed to
|
||||
* another client. That is, ion_free should not be called on this handle until
|
||||
* the buffer has been imported into the other client.
|
||||
*/
|
||||
struct ion_buffer *ion_share(struct ion_client *client,
|
||||
struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_import() - given an buffer in another client, import it
|
||||
* @client: this blocks client
|
||||
* @buffer: the buffer to import (as obtained from ion_share)
|
||||
*
|
||||
* Given a buffer, add it to the client and return the handle to use to refer
|
||||
* to it further. This is called to share a handle from one kernel client to
|
||||
* another.
|
||||
*/
|
||||
struct ion_handle *ion_import(struct ion_client *client,
|
||||
struct ion_buffer *buffer);
|
||||
|
||||
/**
|
||||
* ion_import_fd() - given an fd obtained via ION_IOC_SHARE ioctl, import it
|
||||
* @client: this blocks client
|
||||
* @fd: the fd
|
||||
*
|
||||
* A helper function for drivers that will be recieving ion buffers shared
|
||||
* with them from userspace. These buffers are represented by a file
|
||||
* descriptor obtained as the return from the ION_IOC_SHARE ioctl.
|
||||
* This function coverts that fd into the underlying buffer, and returns
|
||||
* the handle to use to refer to it further.
|
||||
*/
|
||||
struct ion_handle *ion_import_fd(struct ion_client *client, int fd);
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/**
|
||||
* DOC: Ion Userspace API
|
||||
*
|
||||
* create a client by opening /dev/ion
|
||||
* most operations handled via following ioctls
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct ion_allocation_data - metadata passed from userspace for allocations
|
||||
* @len: size of the allocation
|
||||
* @align: required alignment of the allocation
|
||||
* @flags: flags passed to heap
|
||||
* @handle: pointer that will be populated with a cookie to use to refer
|
||||
* to this allocation
|
||||
*
|
||||
* Provided by userspace as an argument to the ioctl
|
||||
*/
|
||||
struct ion_allocation_data {
|
||||
size_t len;
|
||||
size_t align;
|
||||
unsigned int flags;
|
||||
struct ion_handle *handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair
|
||||
* @handle: a handle
|
||||
* @fd: a file descriptor representing that handle
|
||||
*
|
||||
* For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with
|
||||
* the handle returned from ion alloc, and the kernel returns the file
|
||||
* descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace
|
||||
* provides the file descriptor and the kernel returns the handle.
|
||||
*/
|
||||
struct ion_fd_data {
|
||||
struct ion_handle *handle;
|
||||
int fd;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ion_handle_data - a handle passed to/from the kernel
|
||||
* @handle: a handle
|
||||
*/
|
||||
struct ion_handle_data {
|
||||
struct ion_handle *handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ion_custom_data - metadata passed to/from userspace for a custom ioctl
|
||||
* @cmd: the custom ioctl function to call
|
||||
* @arg: additional data to pass to the custom ioctl, typically a user
|
||||
* pointer to a predefined structure
|
||||
*
|
||||
* This works just like the regular cmd and arg fields of an ioctl.
|
||||
*/
|
||||
struct ion_custom_data {
|
||||
unsigned int cmd;
|
||||
unsigned long arg;
|
||||
};
|
||||
|
||||
#define ION_IOC_MAGIC 'I'
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_ALLOC - allocate memory
|
||||
*
|
||||
* Takes an ion_allocation_data struct and returns it with the handle field
|
||||
* populated with the opaque handle for the allocation.
|
||||
*/
|
||||
#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \
|
||||
struct ion_allocation_data)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_FREE - free memory
|
||||
*
|
||||
* Takes an ion_handle_data struct and frees the handle.
|
||||
*/
|
||||
#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_MAP - get a file descriptor to mmap
|
||||
*
|
||||
* Takes an ion_fd_data struct with the handle field populated with a valid
|
||||
* opaque handle. Returns the struct with the fd field set to a file
|
||||
* descriptor open in the current address space. This file descriptor
|
||||
* can then be used as an argument to mmap.
|
||||
*/
|
||||
#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation
|
||||
*
|
||||
* Takes an ion_fd_data struct with the handle field populated with a valid
|
||||
* opaque handle. Returns the struct with the fd field set to a file
|
||||
* descriptor open in the current address space. This file descriptor
|
||||
* can then be passed to another process. The corresponding opaque handle can
|
||||
* be retrieved via ION_IOC_IMPORT.
|
||||
*/
|
||||
#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_IMPORT - imports a shared file descriptor
|
||||
*
|
||||
* Takes an ion_fd_data struct with the fd field populated with a valid file
|
||||
* descriptor obtained from ION_IOC_SHARE and returns the struct with the handle
|
||||
* filed set to the corresponding opaque handle.
|
||||
*/
|
||||
#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, int)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
|
||||
*
|
||||
* Takes the argument of the architecture specific ioctl to call and
|
||||
* passes appropriate userdata for that ioctl
|
||||
*/
|
||||
#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
|
||||
|
||||
#endif /* _LINUX_ION_H */
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* 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 */
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
obj-y += tegra_ion.o
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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);
|
||||
|
Загрузка…
Ссылка в новой задаче