mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 22:52:35 +02:00
Merge branch 'linaro-android-3.10-lsk' of git://git.linaro.org/people/jstultz/android into linux-linaro-lsk-android
This commit is contained in:
commit
e986cff797
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -713,7 +713,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;
|
||||
}
|
||||
|
|
@ -753,7 +753,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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---
|
||||
|
|
@ -16,6 +17,16 @@ config ION_TEST
|
|||
Choose this option to create a device that can be used to test the
|
||||
kernel and device side ION functions.
|
||||
|
||||
config ION_DUMMY
|
||||
bool "Dummy Ion driver"
|
||||
depends on ION
|
||||
help
|
||||
Provides a dummy ION driver that registers the
|
||||
/dev/ion device and some basic heaps. This can
|
||||
be used for testing the ION infrastructure if
|
||||
one doesn't have access to hardware drivers that
|
||||
use ION.
|
||||
|
||||
config ION_TEGRA
|
||||
tristate "Ion for Tegra"
|
||||
depends on ARCH_TEGRA && ION
|
||||
|
|
|
|||
|
|
@ -4,4 +4,7 @@ obj-$(CONFIG_ION_TEST) += ion_test.o
|
|||
ifdef CONFIG_COMPAT
|
||||
obj-$(CONFIG_ION) += compat_ion.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o
|
||||
obj-$(CONFIG_ION_TEGRA) += tegra/
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
158
drivers/staging/android/ion/ion_dummy_driver.c
Normal file
158
drivers/staging/android/ion/ion_dummy_driver.c
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* drivers/gpu/ion/ion_dummy_driver.c
|
||||
*
|
||||
* Copyright (C) 2013 Linaro, 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 <linux/bootmem.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/sizes.h>
|
||||
#include "ion.h"
|
||||
#include "ion_priv.h"
|
||||
|
||||
struct ion_device *idev;
|
||||
struct ion_heap **heaps;
|
||||
|
||||
void *carveout_ptr;
|
||||
void *chunk_ptr;
|
||||
|
||||
struct ion_platform_heap dummy_heaps[] = {
|
||||
{
|
||||
.id = ION_HEAP_TYPE_SYSTEM,
|
||||
.type = ION_HEAP_TYPE_SYSTEM,
|
||||
.name = "system",
|
||||
},
|
||||
{
|
||||
.id = ION_HEAP_TYPE_SYSTEM_CONTIG,
|
||||
.type = ION_HEAP_TYPE_SYSTEM_CONTIG,
|
||||
.name = "system contig",
|
||||
},
|
||||
{
|
||||
.id = ION_HEAP_TYPE_CARVEOUT,
|
||||
.type = ION_HEAP_TYPE_CARVEOUT,
|
||||
.name = "carveout",
|
||||
.size = SZ_4M,
|
||||
},
|
||||
{
|
||||
.id = ION_HEAP_TYPE_CHUNK,
|
||||
.type = ION_HEAP_TYPE_CHUNK,
|
||||
.name = "chunk",
|
||||
.size = SZ_4M,
|
||||
.align = SZ_16K,
|
||||
.priv = (void *)(SZ_16K),
|
||||
},
|
||||
};
|
||||
|
||||
struct ion_platform_data dummy_ion_pdata = {
|
||||
.nr = 4,
|
||||
.heaps = dummy_heaps,
|
||||
};
|
||||
|
||||
static int __init ion_dummy_init(void)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
idev = ion_device_create(NULL);
|
||||
heaps = kzalloc(sizeof(struct ion_heap *) * dummy_ion_pdata.nr,
|
||||
GFP_KERNEL);
|
||||
if (!heaps)
|
||||
return PTR_ERR(heaps);
|
||||
|
||||
|
||||
/* Allocate a dummy carveout heap */
|
||||
carveout_ptr = alloc_pages_exact(
|
||||
dummy_heaps[ION_HEAP_TYPE_CARVEOUT].size,
|
||||
GFP_KERNEL);
|
||||
if (carveout_ptr)
|
||||
dummy_heaps[ION_HEAP_TYPE_CARVEOUT].base =
|
||||
virt_to_phys(carveout_ptr);
|
||||
else
|
||||
pr_err("ion_dummy: Could not allocate carveout\n");
|
||||
|
||||
/* Allocate a dummy chunk heap */
|
||||
chunk_ptr = alloc_pages_exact(
|
||||
dummy_heaps[ION_HEAP_TYPE_CHUNK].size,
|
||||
GFP_KERNEL);
|
||||
if (chunk_ptr)
|
||||
dummy_heaps[ION_HEAP_TYPE_CHUNK].base = virt_to_phys(chunk_ptr);
|
||||
else
|
||||
pr_err("ion_dummy: Could not allocate chunk\n");
|
||||
|
||||
for (i = 0; i < dummy_ion_pdata.nr; i++) {
|
||||
struct ion_platform_heap *heap_data = &dummy_ion_pdata.heaps[i];
|
||||
|
||||
if (heap_data->type == ION_HEAP_TYPE_CARVEOUT &&
|
||||
!heap_data->base)
|
||||
continue;
|
||||
|
||||
if (heap_data->type == ION_HEAP_TYPE_CHUNK && !heap_data->base)
|
||||
continue;
|
||||
|
||||
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]);
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
for (i = 0; i < dummy_ion_pdata.nr; i++) {
|
||||
if (heaps[i])
|
||||
ion_heap_destroy(heaps[i]);
|
||||
}
|
||||
kfree(heaps);
|
||||
|
||||
if (carveout_ptr) {
|
||||
free_pages_exact(carveout_ptr,
|
||||
dummy_heaps[ION_HEAP_TYPE_CARVEOUT].size);
|
||||
carveout_ptr = NULL;
|
||||
}
|
||||
if (chunk_ptr) {
|
||||
free_pages_exact(chunk_ptr,
|
||||
dummy_heaps[ION_HEAP_TYPE_CHUNK].size);
|
||||
chunk_ptr = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit ion_dummy_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
ion_device_destroy(idev);
|
||||
|
||||
for (i = 0; i < dummy_ion_pdata.nr; i++)
|
||||
ion_heap_destroy(heaps[i]);
|
||||
kfree(heaps);
|
||||
|
||||
if (carveout_ptr) {
|
||||
free_pages_exact(carveout_ptr,
|
||||
dummy_heaps[ION_HEAP_TYPE_CARVEOUT].size);
|
||||
carveout_ptr = NULL;
|
||||
}
|
||||
if (chunk_ptr) {
|
||||
free_pages_exact(chunk_ptr,
|
||||
dummy_heaps[ION_HEAP_TYPE_CHUNK].size);
|
||||
chunk_ptr = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(ion_dummy_init);
|
||||
module_exit(ion_dummy_exit);
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -25,6 +26,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/shrinker.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "ion.h"
|
||||
|
||||
|
|
@ -37,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 *
|
||||
|
|
@ -65,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;
|
||||
|
|
@ -97,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,
|
||||
|
|
@ -113,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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -120,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
|
||||
|
|
@ -131,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
|
||||
|
|
@ -159,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 *);
|
||||
|
|
@ -217,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
|
||||
|
|
@ -248,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
|
||||
|
|
@ -304,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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -1819,8 +1819,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
|||
goto error_tgt_fput;
|
||||
|
||||
/* Check if EPOLLWAKEUP is allowed */
|
||||
if ((epds.events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND))
|
||||
epds.events &= ~EPOLLWAKEUP;
|
||||
ep_take_care_of_epollwakeup(&epds);
|
||||
|
||||
/*
|
||||
* We have to check that the file structure underneath the file descriptor
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -61,5 +61,16 @@ struct epoll_event {
|
|||
__u64 data;
|
||||
} EPOLL_PACKED;
|
||||
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev)
|
||||
{
|
||||
if ((epev->events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND))
|
||||
epev->events &= ~EPOLLWAKEUP;
|
||||
}
|
||||
#else
|
||||
static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev)
|
||||
{
|
||||
epev->events &= ~EPOLLWAKEUP;
|
||||
}
|
||||
#endif
|
||||
#endif /* _UAPI_LINUX_EVENTPOLL_H */
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
* manipulate wakelocks on Android.
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
|
|
@ -189,9 +188,6 @@ int pm_wake_lock(const char *buf)
|
|||
size_t len;
|
||||
int ret = 0;
|
||||
|
||||
if (!capable(CAP_BLOCK_SUSPEND))
|
||||
return -EPERM;
|
||||
|
||||
while (*str && !isspace(*str))
|
||||
str++;
|
||||
|
||||
|
|
@ -235,9 +231,6 @@ int pm_wake_unlock(const char *buf)
|
|||
size_t len;
|
||||
int ret = 0;
|
||||
|
||||
if (!capable(CAP_BLOCK_SUSPEND))
|
||||
return -EPERM;
|
||||
|
||||
len = strlen(buf);
|
||||
if (!len)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user