Merge branch 'upstream/android-3.10' into linaro-fixes/android-3.10

This commit is contained in:
John Stultz 2014-01-02 20:11:06 -08:00
commit 3de283fd5a
14 changed files with 279 additions and 128 deletions

View File

@ -85,6 +85,7 @@ CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_TRACE=y
CONFIG_NET_CLS_ACT=y

View File

@ -18,6 +18,7 @@ CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_FUSE_FS=y
CONFIG_GREENASIA_FF=y
CONFIG_HIDRAW=y
CONFIG_HID_A4TECH=y
CONFIG_HID_ACRUX=y
CONFIG_HID_ACRUX_FF=y
@ -95,7 +96,6 @@ CONFIG_PM_RUNTIME=y
CONFIG_PM_WAKELOCKS_LIMIT=0
CONFIG_POWER_SUPPLY=y
CONFIG_SCHEDSTATS=y
CONFIG_SCHED_TRACER=y
CONFIG_SMARTJOYPLUS_FF=y
CONFIG_SND=y
CONFIG_SOUND=y

View File

@ -752,7 +752,7 @@ static ssize_t show_target_loads(
ret += sprintf(buf + ret, "%u%s", tunables->target_loads[i],
i & 0x1 ? ":" : " ");
ret += sprintf(buf + --ret, "\n");
sprintf(buf + ret - 1, "\n");
spin_unlock_irqrestore(&tunables->target_loads_lock, flags);
return ret;
}
@ -792,7 +792,7 @@ static ssize_t show_above_hispeed_delay(
tunables->above_hispeed_delay[i],
i & 0x1 ? ":" : " ");
ret += sprintf(buf + --ret, "\n");
sprintf(buf + ret - 1, "\n");
spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags);
return ret;
}

View File

@ -136,7 +136,7 @@ static struct gpio_desc *gpio_to_desc(unsigned gpio)
*/
static int desc_to_gpio(const struct gpio_desc *desc)
{
return desc->chip->base + gpio_chip_hwgpio(desc);
return desc - &gpio_desc[0];
}
@ -1214,15 +1214,14 @@ int gpiochip_add(struct gpio_chip *chip)
}
}
spin_unlock_irqrestore(&gpio_lock, flags);
#ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&chip->pin_ranges);
#endif
of_gpiochip_add(chip);
unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
goto fail;
@ -1235,6 +1234,9 @@ int gpiochip_add(struct gpio_chip *chip)
chip->label ? : "generic");
return 0;
unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
fail:
/* failures here can mean systems won't boot... */
pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",

View File

@ -1,5 +1,6 @@
menuconfig ION
tristate "Ion Memory Manager"
bool "Ion Memory Manager"
depends on HAVE_MEMBLOCK
select GENERIC_ALLOCATOR
select DMA_SHARED_BUFFER
---help---

View File

@ -59,6 +59,8 @@ struct ion_device {
unsigned long arg);
struct rb_root clients;
struct dentry *debug_root;
struct dentry *heaps_debug_root;
struct dentry *clients_debug_root;
};
/**
@ -69,6 +71,8 @@ struct ion_device {
* @idr: an idr space for allocating handle ids
* @lock: lock protecting the tree of handles
* @name: used for debugging
* @display_name: used for debugging (unique version of @name)
* @display_serial: used for debugging (to make display_name unique)
* @task: used for debugging
*
* A client represents a list of buffers this client may access.
@ -82,6 +86,8 @@ struct ion_client {
struct idr idr;
struct mutex lock;
const char *name;
char *display_name;
int display_serial;
struct task_struct *task;
pid_t pid;
struct dentry *debug_root;
@ -708,6 +714,21 @@ static const struct file_operations debug_client_fops = {
.release = single_release,
};
static int ion_get_client_serial(const struct rb_root *root,
const unsigned char *name)
{
int serial = -1;
struct rb_node *node;
for (node = rb_first(root); node; node = rb_next(node)) {
struct ion_client *client = rb_entry(node, struct ion_client,
node);
if (strcmp(client->name, name))
continue;
serial = max(serial, client->display_serial);
}
return serial + 1;
}
struct ion_client *ion_client_create(struct ion_device *dev,
const char *name)
{
@ -716,9 +737,13 @@ struct ion_client *ion_client_create(struct ion_device *dev,
struct rb_node **p;
struct rb_node *parent = NULL;
struct ion_client *entry;
char debug_name[64];
pid_t pid;
if (!name) {
pr_err("%s: Name cannot be null\n", __func__);
return ERR_PTR(-EINVAL);
}
get_task_struct(current->group_leader);
task_lock(current->group_leader);
pid = task_pid_nr(current->group_leader);
@ -733,21 +758,27 @@ struct ion_client *ion_client_create(struct ion_device *dev,
task_unlock(current->group_leader);
client = kzalloc(sizeof(struct ion_client), GFP_KERNEL);
if (!client) {
if (task)
put_task_struct(current->group_leader);
return ERR_PTR(-ENOMEM);
}
if (!client)
goto err_put_task_struct;
client->dev = dev;
client->handles = RB_ROOT;
idr_init(&client->idr);
mutex_init(&client->lock);
client->name = name;
client->task = task;
client->pid = pid;
client->name = kstrdup(name, GFP_KERNEL);
if (!client->name)
goto err_free_client;
down_write(&dev->lock);
client->display_serial = ion_get_client_serial(&dev->clients, name);
client->display_name = kasprintf(
GFP_KERNEL, "%s-%d", name, client->display_serial);
if (!client->display_name) {
up_write(&dev->lock);
goto err_free_client_name;
}
p = &dev->clients.rb_node;
while (*p) {
parent = *p;
@ -761,13 +792,28 @@ struct ion_client *ion_client_create(struct ion_device *dev,
rb_link_node(&client->node, parent, p);
rb_insert_color(&client->node, &dev->clients);
snprintf(debug_name, 64, "%u", client->pid);
client->debug_root = debugfs_create_file(debug_name, 0664,
dev->debug_root, client,
&debug_client_fops);
client->debug_root = debugfs_create_file(client->display_name, 0664,
dev->clients_debug_root,
client, &debug_client_fops);
if (!client->debug_root) {
char buf[256], *path;
path = dentry_path(dev->clients_debug_root, buf, 256);
pr_err("Failed to create client debugfs at %s/%s\n",
path, client->display_name);
}
up_write(&dev->lock);
return client;
err_free_client_name:
kfree(client->name);
err_free_client:
kfree(client);
err_put_task_struct:
if (task)
put_task_struct(current->group_leader);
return ERR_PTR(-ENOMEM);
}
EXPORT_SYMBOL(ion_client_create);
@ -792,6 +838,8 @@ void ion_client_destroy(struct ion_client *client)
debugfs_remove_recursive(client->debug_root);
up_write(&dev->lock);
kfree(client->display_name);
kfree(client->name);
kfree(client);
}
EXPORT_SYMBOL(ion_client_destroy);
@ -1293,9 +1341,11 @@ static int ion_open(struct inode *inode, struct file *file)
struct miscdevice *miscdev = file->private_data;
struct ion_device *dev = container_of(miscdev, struct ion_device, dev);
struct ion_client *client;
char debug_name[64];
pr_debug("%s: %d\n", __func__, __LINE__);
client = ion_client_create(dev, "user");
snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader));
client = ion_client_create(dev, debug_name);
if (IS_ERR(client))
return PTR_ERR(client);
file->private_data = client;
@ -1443,6 +1493,8 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get,
void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
{
struct dentry *debug_file;
if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma ||
!heap->ops->unmap_dma)
pr_err("%s: can not add heap with invalid ops struct.\n",
@ -1451,21 +1503,40 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
ion_heap_init_deferred_free(heap);
if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink)
ion_heap_init_shrinker(heap);
heap->dev = dev;
down_write(&dev->lock);
/* use negative heap->id to reverse the priority -- when traversing
the list later attempt higher id numbers first */
plist_node_init(&heap->node, -heap->id);
plist_add(&heap->node, &dev->heaps);
debugfs_create_file(heap->name, 0664, dev->debug_root, heap,
&debug_heap_fops);
debug_file = debugfs_create_file(heap->name, 0664,
dev->heaps_debug_root, heap,
&debug_heap_fops);
if (!debug_file) {
char buf[256], *path;
path = dentry_path(dev->heaps_debug_root, buf, 256);
pr_err("Failed to create heap debugfs at %s/%s\n",
path, heap->name);
}
#ifdef DEBUG_HEAP_SHRINKER
if (heap->shrinker.shrink) {
char debug_name[64];
snprintf(debug_name, 64, "%s_shrink", heap->name);
debugfs_create_file(debug_name, 0644, dev->debug_root, heap,
&debug_shrink_fops);
debug_file = debugfs_create_file(
debug_name, 0644, dev->heaps_debug_root, heap,
&debug_shrink_fops);
if (!debug_file) {
char buf[256], *path;
path = dentry_path(dev->heaps_debug_root, buf, 256);
pr_err("Failed to create heap shrinker debugfs at %s/%s\n",
path, debug_name);
}
}
#endif
up_write(&dev->lock);
@ -1494,8 +1565,21 @@ struct ion_device *ion_device_create(long (*custom_ioctl)
}
idev->debug_root = debugfs_create_dir("ion", NULL);
if (!idev->debug_root)
pr_err("ion: failed to create debug files.\n");
if (!idev->debug_root) {
pr_err("ion: failed to create debugfs root directory.\n");
goto debugfs_done;
}
idev->heaps_debug_root = debugfs_create_dir("heaps", idev->debug_root);
if (!idev->heaps_debug_root) {
pr_err("ion: failed to create debugfs heaps directory.\n");
goto debugfs_done;
}
idev->clients_debug_root = debugfs_create_dir("clients",
idev->debug_root);
if (!idev->clients_debug_root)
pr_err("ion: failed to create debugfs clients directory.\n");
debugfs_done:
idev->custom_ioctl = custom_ioctl;
idev->buffers = RB_ROOT;
@ -1509,6 +1593,7 @@ struct ion_device *ion_device_create(long (*custom_ioctl)
void ion_device_destroy(struct ion_device *dev)
{
misc_deregister(&dev->dev);
debugfs_remove_recursive(dev->debug_root);
/* XXX need to free the heaps and clients ? */
kfree(dev);
}

View File

@ -160,10 +160,10 @@ int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot)
void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer)
{
rt_mutex_lock(&heap->lock);
spin_lock(&heap->free_lock);
list_add(&buffer->list, &heap->free_list);
heap->free_list_size += buffer->size;
rt_mutex_unlock(&heap->lock);
spin_unlock(&heap->free_lock);
wake_up(&heap->waitqueue);
}
@ -171,38 +171,55 @@ size_t ion_heap_freelist_size(struct ion_heap *heap)
{
size_t size;
rt_mutex_lock(&heap->lock);
spin_lock(&heap->free_lock);
size = heap->free_list_size;
rt_mutex_unlock(&heap->lock);
spin_unlock(&heap->free_lock);
return size;
}
size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
static size_t _ion_heap_freelist_drain(struct ion_heap *heap, size_t size,
bool skip_pools)
{
struct ion_buffer *buffer, *tmp;
struct ion_buffer *buffer;
size_t total_drained = 0;
if (ion_heap_freelist_size(heap) == 0)
return 0;
rt_mutex_lock(&heap->lock);
spin_lock(&heap->free_lock);
if (size == 0)
size = heap->free_list_size;
list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) {
while (!list_empty(&heap->free_list)) {
if (total_drained >= size)
break;
buffer = list_first_entry(&heap->free_list, struct ion_buffer,
list);
list_del(&buffer->list);
heap->free_list_size -= buffer->size;
if (skip_pools)
buffer->private_flags |= ION_PRIV_FLAG_SHRINKER_FREE;
total_drained += buffer->size;
spin_unlock(&heap->free_lock);
ion_buffer_destroy(buffer);
spin_lock(&heap->free_lock);
}
rt_mutex_unlock(&heap->lock);
spin_unlock(&heap->free_lock);
return total_drained;
}
size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
{
return _ion_heap_freelist_drain(heap, size, false);
}
size_t ion_heap_freelist_shrink(struct ion_heap *heap, size_t size)
{
return _ion_heap_freelist_drain(heap, size, true);
}
static int ion_heap_deferred_free(void *data)
{
struct ion_heap *heap = data;
@ -213,16 +230,16 @@ static int ion_heap_deferred_free(void *data)
wait_event_freezable(heap->waitqueue,
ion_heap_freelist_size(heap) > 0);
rt_mutex_lock(&heap->lock);
spin_lock(&heap->free_lock);
if (list_empty(&heap->free_list)) {
rt_mutex_unlock(&heap->lock);
spin_unlock(&heap->free_lock);
continue;
}
buffer = list_first_entry(&heap->free_list, struct ion_buffer,
list);
list_del(&buffer->list);
heap->free_list_size -= buffer->size;
rt_mutex_unlock(&heap->lock);
spin_unlock(&heap->free_lock);
ion_buffer_destroy(buffer);
}
@ -235,7 +252,7 @@ int ion_heap_init_deferred_free(struct ion_heap *heap)
INIT_LIST_HEAD(&heap->free_list);
heap->free_list_size = 0;
rt_mutex_init(&heap->lock);
spin_lock_init(&heap->free_lock);
init_waitqueue_head(&heap->waitqueue);
heap->task = kthread_run(ion_heap_deferred_free, heap,
"%s", heap->name);
@ -248,6 +265,44 @@ int ion_heap_init_deferred_free(struct ion_heap *heap)
return 0;
}
static int ion_heap_shrink(struct shrinker *shrinker, struct shrink_control *sc)
{
struct ion_heap *heap = container_of(shrinker, struct ion_heap,
shrinker);
int total = 0;
int freed = 0;
int to_scan = sc->nr_to_scan;
if (to_scan == 0)
goto out;
/*
* shrink the free list first, no point in zeroing the memory if we're
* just going to reclaim it. Also, skip any possible page pooling.
*/
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
freed = ion_heap_freelist_shrink(heap, to_scan * PAGE_SIZE) /
PAGE_SIZE;
to_scan -= freed;
if (to_scan < 0)
to_scan = 0;
out:
total = ion_heap_freelist_size(heap) / PAGE_SIZE;
if (heap->ops->shrink)
total += heap->ops->shrink(heap, sc->gfp_mask, to_scan);
return total;
}
void ion_heap_init_shrinker(struct ion_heap *heap)
{
heap->shrinker.shrink = ion_heap_shrink;
heap->shrinker.seeks = DEFAULT_SEEKS;
heap->shrinker.batch = 0;
register_shrinker(&heap->shrinker);
}
struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_heap *heap = NULL;

View File

@ -130,15 +130,11 @@ static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
int nr_to_scan)
{
int nr_freed = 0;
int i;
bool high;
high = !!(gfp_mask & __GFP_HIGHMEM);
if (nr_to_scan == 0)
return ion_page_pool_total(pool, high);
for (i = 0; i < nr_to_scan; i++) {
struct page *page;
@ -153,10 +149,9 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
}
mutex_unlock(&pool->mutex);
ion_page_pool_free_pages(pool, page);
nr_freed += (1 << pool->order);
}
return nr_freed;
return ion_page_pool_total(pool, high);
}
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)

View File

@ -17,6 +17,7 @@
#ifndef _ION_PRIV_H
#define _ION_PRIV_H
#include <linux/device.h>
#include <linux/dma-direction.h>
#include <linux/kref.h>
#include <linux/mm_types.h>
@ -38,6 +39,7 @@ struct ion_buffer *ion_handle_buffer(struct ion_handle *handle);
* @dev: back pointer to the ion_device
* @heap: back pointer to the heap the buffer came from
* @flags: buffer specific flags
* @private_flags: internal buffer specific flags
* @size: size of the buffer
* @priv_virt: private data to the buffer representable as
* a void *
@ -66,6 +68,7 @@ struct ion_buffer {
struct ion_device *dev;
struct ion_heap *heap;
unsigned long flags;
unsigned long private_flags;
size_t size;
union {
void *priv_virt;
@ -98,7 +101,11 @@ void ion_buffer_destroy(struct ion_buffer *buffer);
* @map_user map memory to userspace
*
* allocate, phys, and map_user return 0 on success, -errno on error.
* map_dma and map_kernel return pointer on success, ERR_PTR on error.
* map_dma and map_kernel return pointer on success, ERR_PTR on
* error. @free will be called with ION_PRIV_FLAG_SHRINKER_FREE set in
* the buffer's private_flags when called from a shrinker. In that
* case, the pages being free'd must be truly free'd back to the
* system, not put in a page pool or otherwise cached.
*/
struct ion_heap_ops {
int (*allocate) (struct ion_heap *heap,
@ -114,6 +121,7 @@ struct ion_heap_ops {
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);
int (*shrink)(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan);
};
/**
@ -121,6 +129,17 @@ struct ion_heap_ops {
*/
#define ION_HEAP_FLAG_DEFER_FREE (1 << 0)
/**
* private flags - flags internal to ion
*/
/*
* Buffer is being freed from a shrinker function. Skip any possible
* heap-specific caching mechanism (e.g. page pools). Guarantees that
* any buffer storage that came from the system allocator will be
* returned to the system allocator.
*/
#define ION_PRIV_FLAG_SHRINKER_FREE (1 << 0)
/**
* struct ion_heap - represents a heap in the system
* @node: rb node to put the heap on the device's tree of heaps
@ -132,10 +151,7 @@ struct ion_heap_ops {
* allocating. These are specified by platform data and
* MUST be unique
* @name: used for debugging
* @shrinker: a shrinker for the heap, if the heap caches system
* memory, it must define a shrinker to return it on low
* memory conditions, this includes system memory cached
* in the deferred free lists for heaps that support it
* @shrinker: a shrinker for the heap
* @free_list: free list head if deferred free is used
* @free_list_size size of the deferred free list in bytes
* @lock: protects the free list
@ -160,7 +176,7 @@ struct ion_heap {
struct shrinker shrinker;
struct list_head free_list;
size_t free_list_size;
struct rt_mutex lock;
spinlock_t free_lock;
wait_queue_head_t waitqueue;
struct task_struct *task;
int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);
@ -218,6 +234,16 @@ int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
int ion_heap_buffer_zero(struct ion_buffer *buffer);
int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot);
/**
* ion_heap_init_shrinker
* @heap: the heap
*
* If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag or defines the shrink op
* this function will be called to setup a shrinker to shrink the freelists
* and call the heap's shrink op.
*/
void ion_heap_init_shrinker(struct ion_heap *heap);
/**
* ion_heap_init_deferred_free -- initialize deferred free functionality
* @heap: the heap
@ -249,6 +275,29 @@ void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer);
*/
size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size);
/**
* ion_heap_freelist_shrink - drain the deferred free
* list, skipping any heap-specific
* pooling or caching mechanisms
*
* @heap: the heap
* @size: amount of memory to drain in bytes
*
* Drains the indicated amount of memory from the deferred freelist immediately.
* Returns the total amount freed. The total freed may be higher depending
* on the size of the items in the list, or lower if there is insufficient
* total memory on the freelist.
*
* Unlike with @ion_heap_freelist_drain, don't put any pages back into
* page pools or otherwise cache the pages. Everything must be
* genuinely free'd back to the system. If you're free'ing from a
* shrinker you probably want to use this. Note that this relies on
* the heap.ops.free callback honoring the ION_PRIV_FLAG_SHRINKER_FREE
* flag.
*/
size_t ion_heap_freelist_shrink(struct ion_heap *heap,
size_t size);
/**
* ion_heap_freelist_size - returns the size of the freelist in bytes
* @heap: the heap
@ -305,13 +354,8 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
* @low_count: number of lowmem items in the pool
* @high_items: list of highmem items
* @low_items: list of lowmem items
* @shrinker: a shrinker for the items
* @mutex: lock protecting this struct and especially the count
* item list
* @alloc: function to be used to allocate pageory when the pool
* is empty
* @free: function to be used to free pageory back to the system
* when the shrinker fires
* @gfp_mask: gfp_mask to use from alloc
* @order: order of pages in the pool
* @list: plist node for list of pools

View File

@ -90,7 +90,7 @@ static void free_buffer_page(struct ion_system_heap *heap,
{
bool cached = ion_buffer_cached(buffer);
if (!cached) {
if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) {
struct ion_page_pool *pool = heap->pools[order_to_index(order)];
ion_page_pool_free(pool, page);
} else {
@ -108,6 +108,10 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap,
struct page_info *info;
int i;
info = kmalloc(sizeof(struct page_info), GFP_KERNEL);
if (!info)
return NULL;
for (i = 0; i < num_orders; i++) {
if (size < order_to_size(orders[i]))
continue;
@ -118,11 +122,13 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap,
if (!page)
continue;
info = kmalloc(sizeof(struct page_info), GFP_KERNEL);
info->page = page;
info->order = orders[i];
INIT_LIST_HEAD(&info->list);
return info;
}
kfree(info);
return NULL;
}
@ -140,12 +146,15 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
struct list_head pages;
struct page_info *info, *tmp_info;
int i = 0;
long size_remaining = PAGE_ALIGN(size);
unsigned long size_remaining = PAGE_ALIGN(size);
unsigned int max_order = orders[0];
if (align > PAGE_SIZE)
return -EINVAL;
if (size / PAGE_SIZE > totalram_pages / 2)
return -ENOMEM;
INIT_LIST_HEAD(&pages);
while (size_remaining > 0) {
info = alloc_largest_available(sys_heap, buffer, size_remaining,
@ -200,7 +209,7 @@ static void ion_system_heap_free(struct ion_buffer *buffer)
/* uncached pages come from the page pools, zero them before returning
for security purposes (other allocations are zerod at alloc time */
if (!cached)
if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE))
ion_heap_buffer_zero(buffer);
for_each_sg(table->sgl, sg, table->nents, i)
@ -222,6 +231,23 @@ static void ion_system_heap_unmap_dma(struct ion_heap *heap,
return;
}
static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
int nr_to_scan)
{
struct ion_system_heap *sys_heap;
int nr_total = 0;
int i;
sys_heap = container_of(heap, struct ion_system_heap, heap);
for (i = 0; i < num_orders; i++) {
struct ion_page_pool *pool = sys_heap->pools[i];
nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan);
}
return nr_total;
}
static struct ion_heap_ops system_heap_ops = {
.allocate = ion_system_heap_allocate,
.free = ion_system_heap_free,
@ -230,52 +256,9 @@ static struct ion_heap_ops system_heap_ops = {
.map_kernel = ion_heap_map_kernel,
.unmap_kernel = ion_heap_unmap_kernel,
.map_user = ion_heap_map_user,
.shrink = ion_system_heap_shrink,
};
static int ion_system_heap_shrink(struct shrinker *shrinker,
struct shrink_control *sc) {
struct ion_heap *heap = container_of(shrinker, struct ion_heap,
shrinker);
struct ion_system_heap *sys_heap = container_of(heap,
struct ion_system_heap,
heap);
int nr_total = 0;
int nr_freed = 0;
int i;
if (sc->nr_to_scan == 0)
goto end;
/* shrink the free list first, no point in zeroing the memory if
we're just going to reclaim it */
nr_freed += ion_heap_freelist_drain(heap, sc->nr_to_scan * PAGE_SIZE) /
PAGE_SIZE;
if (nr_freed >= sc->nr_to_scan)
goto end;
for (i = 0; i < num_orders; i++) {
struct ion_page_pool *pool = sys_heap->pools[i];
nr_freed += ion_page_pool_shrink(pool, sc->gfp_mask,
sc->nr_to_scan);
if (nr_freed >= sc->nr_to_scan)
break;
}
end:
/* total number of items is whatever the page pools are holding
plus whatever's in the freelist */
for (i = 0; i < num_orders; i++) {
struct ion_page_pool *pool = sys_heap->pools[i];
nr_total += ion_page_pool_shrink(pool, sc->gfp_mask, 0);
}
nr_total += ion_heap_freelist_size(heap) / PAGE_SIZE;
return nr_total;
}
static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
void *unused)
{
@ -323,10 +306,6 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
heap->pools[i] = pool;
}
heap->heap.shrinker.shrink = ion_system_heap_shrink;
heap->heap.shrinker.seeks = DEFAULT_SEEKS;
heap->heap.shrinker.batch = 0;
register_shrinker(&heap->heap.shrinker);
heap->heap.debug_show = ion_system_heap_debug_show;
return &heap->heap;
err_create_pool:

View File

@ -231,6 +231,7 @@ static int ion_test_release(struct inode *inode, struct file *file)
static const struct file_operations ion_test_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = ion_test_ioctl,
.compat_ioctl = ion_test_ioctl,
.open = ion_test_open,
.release = ion_test_release,
};

View File

@ -20,12 +20,11 @@
#include "../ion.h"
#include "../ion_priv.h"
struct ion_device *idev;
struct ion_mapper *tegra_user_mapper;
int num_heaps;
struct ion_heap **heaps;
static struct ion_device *idev;
static int num_heaps;
static struct ion_heap **heaps;
int tegra_ion_probe(struct platform_device *pdev)
static int tegra_ion_probe(struct platform_device *pdev)
{
struct ion_platform_data *pdata = pdev->dev.platform_data;
int err;
@ -63,7 +62,7 @@ int tegra_ion_probe(struct platform_device *pdev)
return err;
}
int tegra_ion_remove(struct platform_device *pdev)
static int tegra_ion_remove(struct platform_device *pdev)
{
struct ion_device *idev = platform_get_drvdata(pdev);
int i;
@ -81,16 +80,5 @@ static struct platform_driver ion_driver = {
.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);
module_platform_driver(ion_driver);

View File

@ -20,8 +20,6 @@
#include <linux/ioctl.h>
#include <linux/types.h>
typedef int ion_user_handle_t;
/**
* struct ion_test_rw_data - metadata passed to the kernel to read handle
* @ptr: a pointer to an area at least as large as size
@ -34,6 +32,7 @@ struct ion_test_rw_data {
__u64 offset;
__u64 size;
int write;
int __padding;
};
#define ION_IOC_MAGIC 'I'

View File

@ -317,6 +317,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
(clockid != CLOCK_MONOTONIC &&
clockid != CLOCK_REALTIME &&
clockid != CLOCK_REALTIME_ALARM &&
clockid != CLOCK_BOOTTIME &&
clockid != CLOCK_BOOTTIME_ALARM))
return -EINVAL;