HACK: ion: Revert all ion code back to android-hikey-linaro-4.4

Reverts all the ion code to the android-hikey-linaro-4.4 branch.

This adds the hisi ion changes, etc.

Hopefully we can get rid fo this soon.

Signed-off-by: John Stultz <john.stultz@linaro.org>
This commit is contained in:
John Stultz
2017-06-19 17:05:28 -07:00
parent 88768704fb
commit 5634cf8762
33 changed files with 2746 additions and 1083 deletions
+10 -16
View File
@@ -33,22 +33,16 @@ config ION_TEGRA
help
Choose this option if you wish to use ion on an nVidia Tegra.
config ION_POOL_CACHE_POLICY
bool "Ion set page pool cache policy"
depends on ION && X86
default y if X86
help
Choose this option if need to explicity set cache policy of the
pages in the page pool.
config ION_HISI
tristate "Ion for Hisilicon"
tristate "Hisilicon ION driver"
depends on ARCH_HISI && ION
select ION_OF
help
Choose this option if you wish to use ion on Hisilicon Platform.
source "drivers/staging/android/ion/hisilicon/Kconfig"
config ION_OF
bool "Devicetree support for Ion"
depends on ION && OF_ADDRESS
help
Provides base support for defining Ion heaps in devicetree
and setting them up. Also includes functions for platforms
to parse the devicetree and expand for their own custom
extensions
If using Ion and devicetree, you should say Y here
Choose this option if you wish to use ion on an HISI target.
+5 -5
View File
@@ -1,5 +1,4 @@
obj-$(CONFIG_ION) += ion.o ion-ioctl.o ion_heap.o \
ion_page_pool.o ion_system_heap.o \
obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \
ion_carveout_heap.o ion_chunk_heap.o ion_cma_heap.o
obj-$(CONFIG_ION_TEST) += ion_test.o
ifdef CONFIG_COMPAT
@@ -8,6 +7,7 @@ endif
obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o
obj-$(CONFIG_ION_TEGRA) += tegra/
obj-$(CONFIG_ION_HISI) += hisilicon/
obj-$(CONFIG_ION_OF) += ion_of.o
obj-$(CONFIG_ION_HISI) += hisi/
obj-$(CONFIG_ION_HISI_CPUDRAW) += ion_cpudraw_heap.o
obj-$(CONFIG_ION_HISI_SECCM) += ion_seccm_heap.o
obj-$(CONFIG_ION_HISI_DMA_POOL) += ion_dma_pool_heap.o
+134 -3
View File
@@ -39,12 +39,37 @@ struct compat_ion_handle_data {
compat_int_t handle;
};
#ifdef CONFIG_HISI_IOMMU
struct compat_iommu_map_format {
compat_ulong_t iova_start;
compat_ulong_t iova_size;
compat_ulong_t iommu_ptb_base;
compat_ulong_t iommu_iova_base;
compat_ulong_t header_size;
compat_ulong_t phys_page_line;
compat_ulong_t virt_page_line;
compat_ulong_t is_tile;
compat_ulong_t prot;
};
struct compat_ion_map_iommu_data {
compat_int_t handle;
struct compat_iommu_map_format format;
};
#endif
#define COMPAT_ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \
struct compat_ion_allocation_data)
#define COMPAT_ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, \
struct compat_ion_handle_data)
#define COMPAT_ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, \
struct compat_ion_custom_data)
#ifdef CONFIG_HISI_IOMMU
#define COMPAT_ION_IOC_MAP_IOMMU _IOWR(ION_IOC_MAGIC, 8, \
struct compat_ion_map_iommu_data)
#define COMPAT_ION_IOC_UNMAP_IOMMU _IOWR(ION_IOC_MAGIC, 9, \
struct compat_ion_map_iommu_data)
#endif
static int compat_get_ion_allocation_data(
struct compat_ion_allocation_data __user *data32,
@@ -121,6 +146,71 @@ static int compat_get_ion_custom_data(
return err;
};
#ifdef CONFIG_HISI_IOMMU
static int compat_put_ion_map_iommu_data(
struct compat_ion_map_iommu_data __user *data32,
struct ion_map_iommu_data __user *data)
{
compat_ulong_t l;
compat_int_t i;
int err;
err = get_user(i, &data->handle);
err |= put_user(i, &data32->handle);
err |= get_user(l, &data->format.iova_start);
err |= put_user(l, &data32->format.iova_start);
err |= get_user(l, &data->format.iova_size);
err |= put_user(l, &data32->format.iova_size);
err |= get_user(l, &data->format.iommu_ptb_base);
err |= put_user(l, &data32->format.iommu_ptb_base);
err |= get_user(l, &data->format.iommu_iova_base);
err |= put_user(l, &data32->format.iommu_iova_base);
err |= get_user(l, &data->format.header_size);
err |= put_user(l, &data32->format.header_size);
err |= get_user(l, &data->format.phys_page_line);
err |= put_user(l, &data32->format.phys_page_line);
err |= get_user(l, &data->format.virt_page_line);
err |= put_user(l, &data32->format.virt_page_line);
err |= get_user(l, &data->format.is_tile);
err |= put_user(l, &data32->format.is_tile);
err |= get_user(l, &data->format.prot);
err |= put_user(l, &data32->format.prot);
return err;
}
static int compat_get_ion_map_iommu_data(
struct compat_ion_map_iommu_data __user *data32,
struct ion_map_iommu_data __user *data)
{
compat_ulong_t l;
compat_int_t i;
int err;
err = get_user(i, &data32->handle);
err |= put_user(i, &data->handle);
err |= get_user(l, &data32->format.iova_start);
err |= put_user(l, &data->format.iova_start);
err |= get_user(l, &data32->format.iova_size);
err |= put_user(l, &data->format.iova_size);
err |= get_user(l, &data32->format.iommu_ptb_base);
err |= put_user(l, &data->format.iommu_ptb_base);
err |= get_user(l, &data32->format.iommu_iova_base);
err |= put_user(l, &data->format.iommu_iova_base);
err |= get_user(l, &data->format.header_size);
err |= put_user(l, &data32->format.header_size);
err |= get_user(l, &data32->format.phys_page_line);
err |= put_user(l, &data->format.phys_page_line);
err |= get_user(l, &data32->format.virt_page_line);
err |= put_user(l, &data->format.virt_page_line);
err |= get_user(l, &data32->format.is_tile);
err |= put_user(l, &data->format.is_tile);
err |= get_user(l, &data32->format.prot);
err |= put_user(l, &data->format.prot);
return err;
}
#endif
long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
long ret;
@@ -137,7 +227,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
if (!data)
if (data == NULL)
return -EFAULT;
err = compat_get_ion_allocation_data(data32, data);
@@ -156,7 +246,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
if (!data)
if (data == NULL)
return -EFAULT;
err = compat_get_ion_handle_data(data32, data);
@@ -173,7 +263,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
if (!data)
if (data == NULL)
return -EFAULT;
err = compat_get_ion_custom_data(data32, data);
@@ -183,10 +273,51 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return filp->f_op->unlocked_ioctl(filp, ION_IOC_CUSTOM,
(unsigned long)data);
}
#ifdef CONFIG_HISI_IOMMU
case COMPAT_ION_IOC_MAP_IOMMU:
{
struct compat_ion_map_iommu_data __user *data32;
struct ion_map_iommu_data __user *data;
int err;
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
if (data == NULL)
return -EFAULT;
err = compat_get_ion_map_iommu_data(data32, data);
if (err)
return err;
ret = filp->f_op->unlocked_ioctl(filp, ION_IOC_MAP_IOMMU,
(unsigned long)data);
err = compat_put_ion_map_iommu_data(data32, data);
return ret ? ret : err;
}
case COMPAT_ION_IOC_UNMAP_IOMMU:
{
struct compat_ion_map_iommu_data __user *data32;
struct ion_map_iommu_data __user *data;
int err;
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
if (data == NULL)
return -EFAULT;
err = compat_get_ion_map_iommu_data(data32, data);
if (err)
return err;
ret = filp->f_op->unlocked_ioctl(filp, ION_IOC_UNMAP_IOMMU,
(unsigned long)data);
err = compat_put_ion_map_iommu_data(data32, data);
return ret ? ret : err;
}
#endif
case ION_IOC_SHARE:
case ION_IOC_MAP:
case ION_IOC_IMPORT:
case ION_IOC_SYNC:
case ION_IOC_INV:
return filp->f_op->unlocked_ioctl(filp, cmd,
(unsigned long)compat_ptr(arg));
default:
@@ -1,51 +0,0 @@
Ion Memory Manager
Ion is a memory manager that allows for sharing of buffers via dma-buf.
Ion allows for different types of allocation via an abstraction called
a 'heap'. A heap represents a specific type of memory. Each heap has
a different type. There can be multiple instances of the same heap
type.
Specific heap instances are tied to heap IDs. Heap IDs are not to be specified
in the devicetree.
Required properties for Ion
- compatible: "linux,ion" PLUS a compatible property for the device
All child nodes of a linux,ion node are interpreted as heaps
required properties for heaps
- compatible: compatible string for a heap type PLUS a compatible property
for the specific instance of the heap. Current heap types
-- linux,ion-heap-system
-- linux,ion-heap-system-contig
-- linux,ion-heap-carveout
-- linux,ion-heap-chunk
-- linux,ion-heap-dma
-- linux,ion-heap-custom
Optional properties
- memory-region: A phandle to a memory region. Required for DMA heap type
(see reserved-memory.txt for details on the reservation)
Example:
ion {
compatbile = "hisilicon,ion", "linux,ion";
ion-system-heap {
compatbile = "hisilicon,system-heap", "linux,ion-heap-system"
};
ion-camera-region {
compatible = "hisilicon,camera-heap", "linux,ion-heap-dma"
memory-region = <&camera_region>;
};
ion-fb-region {
compatbile = "hisilicon,fb-heap", "linux,ion-heap-dma"
memory-region = <&fb_region>;
};
}
@@ -0,0 +1,7 @@
ccflags-y += -I$(srctree)/drivers/staging/android/ion
ccflags-y += -I$(srctree)/drivers/hisi/ap/platform/$(TARGET_PRODUCT)
obj-$(CONFIG_HISI_SMARTPOOL_OPT)+= hisi_ion_smart_pool.o
obj-y += hisi_cpudraw_alloc.o
obj-$(CONFIG_ION_HISI)+= of_hisi_ion.o
@@ -0,0 +1,341 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include "hisi_cpudraw_alloc.h"
#define KERNEL_DEBUG
#if defined(KERNEL_DEBUG)
#define ALOGD(format, arg...) pr_info("[cpubuffer] " format, ##arg);
#define ALOGD_INFO(format, arg...) pr_info("[cpubuffer] " format, ##arg);
#else
#define ALOGD(format, arg...)
#define ALOGD_INFO(format, arg...)
#endif
struct list_head idlenode_list;
struct list_head allocatednode_list;
struct mutex list_lock;
static int get_split_mode(mem_node_t * node, int bytew, int byteh)
{
int split_mode;
if(bytew < node->cpubuf.bytew){
split_mode = SPLIT_MODE_W;
}else if(byteh <= node->cpubuf.byteh){
split_mode = SPLIT_MODE_H;
}else{
split_mode = SPLIT_MODE_NULL;
}
ALOGD_INFO("cpubuffer info:split_mode=%d\n", split_mode);
return split_mode;
}
void memlist_dump(void)
{
mem_node_t *node;
mutex_lock(&list_lock);
if(list_empty(&idlenode_list)){
ALOGD("DUMP_IDLE:idlenode_list is empty\n");
}
if(list_empty(&allocatednode_list)){
ALOGD("DUMP_BUSY:allocatednode_list is empty\n");
}
list_for_each_entry(node, &idlenode_list, node_head){
ALOGD("DUMP_IDLE:phy=0x%8lx w=%6d h=%6d stride=%6d size=%6d ref=%d this=0x%p father=0x%p\n",
node->cpubuf.phy_addr,
node->cpubuf.bytew,
node->cpubuf.byteh,
node->cpubuf.stride,
node->cpubuf.size,
node->ref,
node->thisnode,
node->father
);
}
list_for_each_entry(node, &allocatednode_list, node_head){
ALOGD("DUMP_BUSY:phy=0x%8lx w=%6d h=%6d stride=%6d size=%6d ref=%d this=0x%p father=0x%p\n",
node->cpubuf.phy_addr,
node->cpubuf.bytew,
node->cpubuf.byteh,
node->cpubuf.stride,
node->cpubuf.size,
node->ref,
node->thisnode,
node->father
);
}
mutex_unlock(&list_lock);
}
void memlist_init(void)
{
INIT_LIST_HEAD(&idlenode_list);
INIT_LIST_HEAD(&allocatednode_list);
mutex_init(&list_lock);
}
static mem_node_t *split_node(mem_node_t *father, int bytew, int byteh)
{
int split_mode;
mem_node_t *node[2];
int newbytew[2];
int newbyteh[2];
int newaddr[2];
int i;
if(father->cpubuf.bytew < bytew || father->cpubuf.byteh < byteh){
ALOGD_INFO("cpubuffer info:idle memory not enough left=(w=%d h=%d) need=(w=%d h=%d)\n",
father->cpubuf.bytew, father->cpubuf.byteh, bytew, byteh);
return NULL;
}
split_mode = get_split_mode(father, bytew, byteh);
if(split_mode != SPLIT_MODE_NULL){
if(split_mode == SPLIT_MODE_W){
newbytew[0] = bytew;
newbytew[1] = father->cpubuf.bytew - bytew;
newaddr[0] = father->cpubuf.phy_addr;
newaddr[1] = father->cpubuf.phy_addr + bytew;
newbyteh[0] = father->cpubuf.byteh;
newbyteh[1] = father->cpubuf.byteh;
}else{
newbyteh[0] = byteh;
newbyteh[1] = father->cpubuf.byteh - byteh;
newaddr[0] = father->cpubuf.phy_addr;
newaddr[1] = father->cpubuf.phy_addr + father->cpubuf.stride*byteh;
newbytew[0] = father->cpubuf.bytew;
newbytew[1] = father->cpubuf.bytew;
}
for(i = 0; i < 2; i++){
node[i] = (mem_node_t *)kmalloc(sizeof(mem_node_t), GFP_KERNEL);
if(node[i] == NULL){
return NULL;
}
node[i]->father = father;
node[i]->thisnode = node[i];
node[i]->ref = father->ref + 1;
node[i]->cpubuf.phy_addr = newaddr[i];
node[i]->cpubuf.bytew = newbytew[i];
node[i]->cpubuf.byteh = newbyteh[i];
node[i]->cpubuf.stride = father->cpubuf.stride;
node[i]->cpubuf.size = newbytew[i]*newbyteh[i];
}
list_del(&father->node_head);
list_add(&node[1]->node_head, &idlenode_list);
return node[0];
}
return NULL;
}
static mem_node_t *node_alloc_direct(struct gen_pool *pool, int size, int stride, int byteh)
{
int phy_addr = 0;
mem_node_t *newnode = NULL;
newnode = (mem_node_t *)kmalloc(sizeof(mem_node_t), GFP_KERNEL); //replace with kmalloc
if(newnode == NULL) {
return NULL;
}
phy_addr = gen_pool_alloc(pool, size); //gen_pool_alloc
if(phy_addr == 0){
kfree(newnode);
ALOGD("cpubuffer err:no more memory ,need size=%d\n", size);
return NULL;
}
ALOGD_INFO("MEMORY info:direct alloc node=0x%p size=%d\n", newnode, size);
newnode->thisnode = newnode;
newnode->father = NULL;
newnode->ref = 0;
newnode->cpubuf.phy_addr = phy_addr;
newnode->cpubuf.stride = stride;
newnode->cpubuf.bytew = stride;
newnode->cpubuf.byteh = byteh;
newnode->cpubuf.size = size;
return newnode;
}
static mem_node_t *node_alloc(struct gen_pool *pool, int size, int bytew, int byteh)
{
int stride = size / byteh;
mem_node_t *node = NULL, *newnode = NULL;
if(size < bytew*byteh || stride < bytew){
ALOGD("cpubuffer err:alloc parameter err size=%d w=%d h=%d\n", size, bytew, byteh);
return NULL;
}
do{
list_for_each_entry(node, &idlenode_list, node_head){
if(stride == node->cpubuf.stride){
newnode = split_node(node, bytew, byteh);
if(newnode != NULL){
return newnode;
}
}
}
newnode= node_alloc_direct(pool, size, stride, byteh);
if(newnode != NULL){
list_add(&newnode->node_head, &idlenode_list);
}
} while(newnode != NULL);
return NULL;
}
static mem_node_t * memge_node(mem_node_t * twins, mem_node_t *freenode)
{
mem_node_t *father;
if(twins->father != freenode->father){
ALOGD("cpubuffer err:merge node but different father\n");
return NULL;
}
father = freenode->father;
list_del(&twins->node_head);
twins->cpubuf.thisnode = NULL;
freenode->cpubuf.thisnode = NULL;
kfree(twins);
kfree(freenode);
return father;
}
static void node_free_direct(struct gen_pool *pool, mem_node_t * tofreenode)
{
mem_node_t *father = tofreenode;
if(father == NULL){
return;
}
pr_info("father->ref=%d\n", father->ref);
if(father != NULL && father->ref == 0){
pr_info("MEMORY info:direct free node=0x%p size=%d\n", father, father->cpubuf.size);
father->cpubuf.thisnode = NULL;
gen_pool_free(pool, father->cpubuf.phy_addr, father->cpubuf.size);
kfree(father);
}
}
static void node_free(struct gen_pool *pool, mem_node_t * tofreenode)
{
mem_node_t *freenode = tofreenode;
mem_node_t *father = NULL;
if(tofreenode == NULL){
return;
}
do{
mem_node_t *twins = NULL;
mem_node_t *node = NULL;
list_for_each_entry(node, &idlenode_list, node_head){
if(node->father == freenode->father){
twins = node;
}
}
if(twins == NULL){
list_add(&freenode->node_head, &idlenode_list);
father = NULL;
}else{
int ref;
ref = twins->ref;
father = memge_node(twins, freenode);
freenode = father;
ALOGD_INFO("cpubuffer info:merge this_ref=%d father_ref=%d father=0x%p\n", ref, father->ref, father);
}
}while(father != NULL && father->ref != 0);
node_free_direct(pool, father);
}
unsigned long cpubuffer_alloc(struct gen_pool *pool, int size, int bytew, int byteh)
{
mem_node_t *node = NULL;
cpubuf_handle_t * cpubuf = NULL;
mutex_lock(&list_lock);
node = node_alloc(pool, size , bytew, byteh);
if(node != NULL){
node->cpubuf.thisnode = (void *)node->thisnode;
cpubuf = &node->cpubuf;
list_add(&node->node_head, &allocatednode_list);
mutex_unlock(&list_lock);
return cpubuf->phy_addr;
}
mutex_unlock(&list_lock);
return 0;
}
int cpubuffer_free(struct gen_pool *pool, unsigned long phy_addr)
{
mem_node_t *node = NULL;
cpubuf_handle_t *cpubuf = NULL;
pr_info("free addr=0x%lx\n", phy_addr);
mutex_lock(&list_lock);
list_for_each_entry(node, &allocatednode_list, node_head){
pr_info("free node_phy_addr=0x%lx addr=0x%lx\n", node->cpubuf.phy_addr, phy_addr);
if(node->cpubuf.phy_addr == phy_addr){
cpubuf = &node->cpubuf;
break;
}
}
list_del(&node->node_head);
mutex_unlock(&list_lock);
if(cpubuf == NULL){
pr_info("1free addr=0x%lx\n", phy_addr);
return -1;
}
if(node != cpubuf->thisnode){
pr_info("2free addr=0x%lx\n", phy_addr);
return -1;
}
mutex_lock(&list_lock);
if(cpubuf->stride == 0 && cpubuf->bytew == 0 && cpubuf->byteh == 0){
node_free_direct(pool, node);
}else{
node_free(pool, node);
}
mutex_unlock(&list_lock);
return 0;
}
@@ -0,0 +1,38 @@
#ifndef _CPUBUFFER_ALLOC_H_
#define _CPUBUFFER_ALLOC_H_
#include <linux/genalloc.h>
#include <linux/list.h>
enum{
SPLIT_MODE_NULL = 0x0,
SPLIT_MODE_W,
SPLIT_MODE_H
};
typedef struct cpubuf_handle_t{
unsigned long phy_addr;
int bytew; // 256 bytes aligned
int byteh; // 16 pixel aligned
int stride;
int size; //only for ref = 0 node
void *thisnode; //only for free
}cpubuf_handle_t;
typedef struct mem_node_t{
struct list_head node_head;
struct mem_node_t *thisnode;
struct mem_node_t *father;
unsigned int ref;
cpubuf_handle_t cpubuf;
}mem_node_t;
void memlist_init(void);
void memlist_dump(void);
unsigned long cpubuffer_alloc(struct gen_pool *pool, int size, int bytew, int byteh);
int cpubuffer_free(struct gen_pool *pool, unsigned long phy_addr);
#endif //_CPUBUFFER_ALLOC_H_
@@ -0,0 +1,69 @@
static size_t ion_client_total(struct ion_client *client)
{
size_t size = 0;
struct rb_node *n;
mutex_lock(&client->lock);
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
struct ion_handle *handle = rb_entry(n,
struct ion_handle, node);
if (!(handle->import) && (handle->buffer->heap->type !=
ION_HEAP_TYPE_CARVEOUT)) {
if (handle->buffer->cpudraw_sg_table)
size += handle->buffer->cpu_buffer_size;
else
size += handle->buffer->size;
}
}
mutex_unlock(&client->lock);
return size;
}
unsigned long hisi_ion_total(void)
{
return (unsigned long)atomic_long_read(&ion_total_size);
}
int hisi_ion_memory_info(bool verbose)
{
struct rb_node *n;
struct ion_device *dev = get_ion_device();
if (!dev)
return -1;
pr_info("ion total size:%ld\n", atomic_long_read(&ion_total_size));
if (!verbose)
return 0;
down_read(&dev->client_lock);
for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
struct ion_client *client = rb_entry(n,
struct ion_client, node);
size_t size = ion_client_total(client);
if (!size)
continue;
if (client->task) {
char task_comm[TASK_COMM_LEN];
get_task_comm(task_comm, client->task);
pr_info("%16.s %16u %16zu\n",
task_comm, client->pid, size);
} else {
pr_info("%16.s %16u %16zu\n",
client->name, client->pid, size);
}
}
up_read(&dev->client_lock);
mutex_lock(&dev->buffer_lock);
for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
node);
if (!buffer->handle_count &&
(buffer->heap->type != ION_HEAP_TYPE_CARVEOUT))
pr_info("%16.s %16u %16zu\n", buffer->task_comm,
buffer->pid, buffer->size);
}
mutex_unlock(&dev->buffer_lock);
return 0;
}
@@ -0,0 +1,346 @@
/*
*
* Copyright (C) 2016 hisilicon, 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.
*
*/
#define pr_fmt(fmt) "smartpool: " fmt
#include <asm/page.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/hisi/ion-iommu.h>
#include <linux/sizes.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include "ion.h"
#include "hisi_ion_smart_pool.h"
/*for pclin*/
/*lint -save -e846 -e514 -e866 -e30 -e84 -e712 -e701 -e40 -e578 -e528*/
/*lint -save -e522 -e838 -e737 -e84 -e774 -e845 -e527 -e531 -e702 -e753*/
/*lint -save -e713 -e732 -e438 -e778 -e708 -e21 -e528 -e756*/
static bool smart_pool_enable = true;
static int smart_pool_alloc_size;
struct task_struct *smart_pool_thread;
static wait_queue_head_t smart_pool_wait;
static unsigned int smart_pool_wait_flag;
int smart_pool_water_mark = 24 * 64 * 4;
static unsigned int smart_pool_orders[] = {9, 8, 4, 2, 0};
static const int smart_pool_num_orders = ARRAY_SIZE(smart_pool_orders);
#define SMART_POOL_MIN(x, y) (((x) < (y)) ? (x) : (y))
bool ion_smart_is_graphic_buffer(struct ion_buffer *buffer)
{
if (NULL == buffer) {
pr_err("%s: buffer is NULL!\n", __func__);
return false;
}
return !!(buffer->flags & ION_FLAG_GRAPHIC_BUFFER);
}
void ion_smart_set_water_mark(int water_mark)
{
smart_pool_water_mark = water_mark;
}
static int sp_order_to_index(unsigned int order)
{
int i;
for (i = 0; i < smart_pool_num_orders; i++) {
if (order == smart_pool_orders[i])
return i;
}
BUG();
return -1;
}
static inline unsigned long sp_order_to_size(int order)
{
return PAGE_SIZE << order;
}
static int sp_ion_page_pool_total(struct ion_page_pool *pool)
{
int count;
if (NULL == pool) {
pr_err("%s: pool is NULL!\n", __func__);
return 0;
}
count = pool->low_count + pool->high_count;
return count << pool->order;
}
static int sp_pool_total_pages(struct ion_smart_pool *pool)
{
int i;
int count = 0;
if (NULL == pool) {
pr_err("%s: pool is NULL!\n", __func__);
return 0;
}
for (i = 0; i < smart_pool_num_orders; i++)
count += sp_ion_page_pool_total(pool->pools[i]);
return count;
}
void ion_smart_sp_init_page(struct page *page)
{
unsigned long len;
if (NULL == page) {
pr_err("%s: page is NULL!\n", __func__);
return;
}
len = PAGE_SIZE << compound_order(page);
memset(page_address(page), 0, len);
__flush_dcache_area(page_address(page), len);
}
static int sp_fill_pool_once(struct ion_page_pool *pool)
{
struct page *page;
if (NULL == pool) {
pr_err("%s: pool is NULL!\n", __func__);
return -ENOENT;
}
page = ion_page_pool_alloc_pages(pool);
if (NULL == page)
return -ENOMEM;
ion_smart_sp_init_page(page);
ion_page_pool_free(pool, page);
return 0;
}
static int ion_smart_pool_kworkthread(void *p)
{
int i;
struct ion_smart_pool *pool;
int ret;
if (NULL == p) {
pr_err("%s: p is NULL!\n", __func__);
return 0;
}
pool = (struct ion_smart_pool *)p;
while (true) {
ret = wait_event_interruptible(smart_pool_wait,
(smart_pool_wait_flag == 1));
if (ret < 0)
continue;
smart_pool_wait_flag = 0;
for (i = 0; i < smart_pool_num_orders; i++) {
while (sp_pool_total_pages(pool) <
smart_pool_water_mark) {
if (sp_fill_pool_once(pool->pools[i]) < 0)
break;
}
}
for (i = 2; i < smart_pool_num_orders; i++) {
while (sp_ion_page_pool_total(pool->pools[i]) <
LOWORDER_WATER_MASK) {
if (sp_fill_pool_once(pool->pools[i]) < 0)
break;
}
}
}
return 0;
}
struct page *ion_smart_pool_allocate(struct ion_smart_pool *pool,
unsigned long size, unsigned int max_order)
{
int i;
struct page *page;
if (NULL == pool) {
pr_err("%s: pool is NULL!\n", __func__);
return NULL;
}
for (i = 0; i < smart_pool_num_orders; i++) {
if (size < sp_order_to_size(smart_pool_orders[i]))
continue;
if (max_order < smart_pool_orders[i])
continue;
page = ion_page_pool_alloc(pool->pools[i]);
if (!page)
continue;
if (smart_pool_alloc_size) {
smart_pool_alloc_size +=
PAGE_SIZE << compound_order(page);
}
return page;
}
return NULL;
}
void ion_smart_pool_wakeup_process(void)
{
if (!smart_pool_enable)
return;
smart_pool_wait_flag = 1;
wake_up_interruptible(&smart_pool_wait);
}
void ion_smart_pool_all_free(struct ion_smart_pool *pool, gfp_t gfp_mask,
int nr_to_scan)
{
int i;
if (NULL == pool) {
pr_err("%s: smart_pool is NULL!\n", __func__);
return;
}
for (i = 0; i < smart_pool_num_orders; i++)
ion_page_pool_shrink(pool->pools[i], gfp_mask, nr_to_scan);
}
int ion_smart_pool_free(struct ion_smart_pool *pool, struct page *page)
{
int order;
if (!smart_pool_enable) {
ion_smart_pool_all_free(pool, __GFP_HIGHMEM, MAX_POOL_SIZE);
return -1;
}
if ((NULL == pool) || (NULL == page)) {
pr_err("%s: pool/page is NULL!\n", __func__);
return -1;
}
order = compound_order(page);
if (sp_pool_total_pages(pool) < MAX_POOL_SIZE) {
ion_smart_sp_init_page(page);
ion_page_pool_free(pool->pools[sp_order_to_index(order)], page);
return 0;
}
return -1;
}
int ion_smart_pool_shrink(struct ion_smart_pool *smart_pool,
struct ion_page_pool *pool, gfp_t gfp_mask,
int nr_to_scan)
{
int nr_max_free;
int nr_to_free;
int nr_total = 0;
if ((NULL == smart_pool) || (NULL == pool)) {
pr_err("%s: smartpool/pool is NULL!\n", __func__);
return 0;
}
if (nr_to_scan == 0)
return ion_page_pool_shrink(pool, gfp_mask, 0);
nr_max_free = sp_pool_total_pages(smart_pool) -
(smart_pool_water_mark + LOWORDER_WATER_MASK);
nr_to_free = SMART_POOL_MIN(nr_max_free, nr_to_scan);
if (nr_to_free <= 0)
return 0;
nr_total = ion_page_pool_shrink(pool, gfp_mask, nr_to_free);
return nr_total;
}
void ion_smart_pool_debug_show_total(struct seq_file *s,
struct ion_smart_pool *smart_pool)
{
if ((NULL == s) || (NULL == smart_pool)) {
pr_err("%s: s/smart_pool is NULL!\n", __func__);
return;
}
seq_puts(s, "----------------------------------------------------\n");
seq_printf(s, "in smart pool = %d total\n",
sp_pool_total_pages(smart_pool) * 4 / 1024);
}
struct ion_smart_pool *ion_smart_pool_create(void)
{
struct ion_smart_pool *smart_pool =
kzalloc(sizeof(struct ion_smart_pool) +
sizeof(struct ion_page_pool *) * smart_pool_num_orders,
GFP_KERNEL);
bool graphic_buffer_flag = true;
if (NULL == smart_pool) {
pr_err("%s: smart_pool is NULL!\n", __func__);
return NULL;
}
if (ion_system_heap_create_pools(smart_pool->pools,
graphic_buffer_flag))
goto free_heap;
init_waitqueue_head(&smart_pool_wait);
smart_pool_thread = kthread_run(ion_smart_pool_kworkthread, smart_pool,
"%s", "smartpool");
if (IS_ERR(smart_pool_thread)) {
pr_err("%s: kthread_create failed!\n", __func__);
goto destroy_pools;
}
ion_smart_pool_wakeup_process();
return smart_pool;
destroy_pools:
ion_system_heap_destroy_pools(smart_pool->pools);
free_heap:
kfree(smart_pool);
smart_pool = NULL;
return NULL;
}
module_param_named(debug_smart_pool_enable, smart_pool_enable, bool, 0644);
MODULE_PARM_DESC(debug_smart_pool_enable, "enable smart pool");
module_param_named(debug_smart_pool_alloc_size, smart_pool_alloc_size, int,
0644);
MODULE_PARM_DESC(debug_smart_pool_alloc_size, "alloc size from smartpool");
/*lint -restore*/
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 Hislicon, 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_SMART_POOL_H
#define _ION_SMART_POOL_H
#include <linux/kthread.h>
#include <linux/types.h>
#include "ion_priv.h"
#define LOWORDER_WATER_MASK (64*4)
#define MAX_POOL_SIZE (128*64*4)
struct ion_smart_pool {
struct ion_page_pool *pools[0];
};
bool ion_smart_is_graphic_buffer(struct ion_buffer *buffer);
void ion_smart_pool_debug_show_total(struct seq_file *s,
struct ion_smart_pool *smart_pool);
void ion_smart_sp_init_page(struct page *page);
struct page *ion_smart_pool_allocate(struct ion_smart_pool *pool,
unsigned long size,
unsigned int max_order);
int ion_smart_pool_free(struct ion_smart_pool *pool, struct page *page);
int ion_smart_pool_shrink(struct ion_smart_pool *smart_pool,
struct ion_page_pool *pool, gfp_t gfp_mask,
int nr_to_scan);
struct ion_smart_pool *ion_smart_pool_create(void);
void ion_smart_pool_wakeup_process(void);
void ion_smart_set_water_mark(int water_mark);
#endif /* _ION_SMART_POOL_H */
@@ -0,0 +1,413 @@
/*
* Hisilicon hisi ION Driver
*
* Copyright (c) 2015 Hisilicon Limited.
*
* Author: Chen Feng <puck.chen@hisilicon.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define pr_fmt(fmt) "Ion: " fmt
#include <linux/export.h>
#include <linux/err.h>
#include <linux/hisi/hisi_ion.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/sched.h>
#include <linux/rwsem.h>
#include <linux/uaccess.h>
#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <linux/compat.h>
#include <linux/sizes.h>
#include <ion_priv.h>
#include <linux/of_reserved_mem.h>
#include <linux/of_fdt.h>
#include <asm/cputype.h>
#define MAX_HISI_ION_DYNAMIC_AREA_NAME_LEN 64
struct hisi_ion_dynamic_area {
phys_addr_t base;
unsigned long size;
char name[MAX_HISI_ION_DYNAMIC_AREA_NAME_LEN];
};
struct hisi_ion_type_table {
const char *name;
enum ion_heap_type type;
};
static const struct hisi_ion_type_table ion_type_table[] = {
{"ion_system", ION_HEAP_TYPE_SYSTEM},
{"ion_system_contig", ION_HEAP_TYPE_SYSTEM_CONTIG},
{"ion_carveout", ION_HEAP_TYPE_CARVEOUT},
{"ion_chunk", ION_HEAP_TYPE_CHUNK},
{"ion_dma", ION_HEAP_TYPE_DMA},
{"ion_custom", ION_HEAP_TYPE_CUSTOM},
};
static struct ion_device *idev;
static int num_heaps;
static struct ion_heap **heaps;
static struct ion_platform_heap **heaps_data;
#define MAX_HISI_ION_DYNAMIC_AREA_NUM 5
static struct hisi_ion_dynamic_area ion_dynamic_area_table[MAX_HISI_ION_DYNAMIC_AREA_NUM];
static int ion_dynamic_area_count = 0;
static int add_dynamic_area(phys_addr_t base, unsigned long len, const char* name)
{
int ret = 0;
int i = ion_dynamic_area_count;
if (i < MAX_HISI_ION_DYNAMIC_AREA_NUM) {
ion_dynamic_area_table[i].base = base;
ion_dynamic_area_table[i].size = len;
strncpy(ion_dynamic_area_table[i].name, name,
MAX_HISI_ION_DYNAMIC_AREA_NAME_LEN-1);
ion_dynamic_area_table[i].name[MAX_HISI_ION_DYNAMIC_AREA_NAME_LEN-1] = '\0';
pr_err("insert heap-name %s \n", ion_dynamic_area_table[i].name);
ion_dynamic_area_count ++;
return ret;
}
return -EFAULT;
}
static struct hisi_ion_dynamic_area* find_dynamic_area_by_name(const char* name)
{
int i = 0;
if (!name) {
return NULL;
}
for (; i < MAX_HISI_ION_DYNAMIC_AREA_NUM; i++) {
pr_err("name = %s, table name %s \n", name, ion_dynamic_area_table[i].name);
if (!strcmp(name, ion_dynamic_area_table[i].name)) {
return &ion_dynamic_area_table[i];
}
}
return NULL;
}
static int __init hisi_ion_reserve_area(struct reserved_mem *rmem)
{
char *status = NULL;
int namesize = 0;
const char* heapname;
status = (char *)of_get_flat_dt_prop(rmem->fdt_node, "status", NULL);
if (status && (strncmp(status, "ok", strlen("ok")) != 0))
return 0;
heapname = of_get_flat_dt_prop(rmem->fdt_node, "heap-name", &namesize);
if (!heapname || (namesize <= 0)) {
pr_err("no 'heap-name' property namesize=%d\n", namesize);
return -EFAULT;
}
pr_info("base 0x%llx, size is 0x%llx, node name %s, heap-name %s namesize %d,"
"[%d][%d][%d][%d]\n",
rmem->base, rmem->size, rmem->name, heapname, namesize,
heapname[0],heapname[1],heapname[2],heapname[3] );
if (add_dynamic_area(rmem->base, rmem->size, heapname)) {
pr_err("fail to add to dynamic area \n");
return -EFAULT;
}
return 0;
}
RESERVEDMEM_OF_DECLARE(hisi_ion, "hisi_ion", hisi_ion_reserve_area);
struct ion_device *get_ion_device(void) {
return idev;
}
static void ion_pm_init(void)
{
return;
}
void ion_flush_all_cpus_caches(void)
{
return;
}
struct ion_client *hisi_ion_client_create(const char *name)
{
return ion_client_create(idev, name);
}
EXPORT_SYMBOL(hisi_ion_client_create);
static long hisi_ion_custom_ioctl(struct ion_client *client,
unsigned int cmd,
unsigned long arg)
{
int ret = 0;
return ret;
}
extern int hisi_ion_enable_iommu(struct platform_device *pdev);
static int get_type_by_name(const char *name, enum ion_heap_type *type)
{
int i;
for (i = 0; i < ARRAY_SIZE(ion_type_table); i++) {
if (strcmp(name, ion_type_table[i].name))
continue;
*type = ion_type_table[i].type;
return 0;
}
return -EINVAL;
}
static int hisi_set_platform_data(struct platform_device *pdev)
{
unsigned int base = 0;
unsigned int size = 0;
unsigned int id = 0;
const char *heap_name;
const char *type_name;
const char *status;
enum ion_heap_type type = 0;
int ret = 0;
struct device_node *np;
struct device_node *phandle_node;
struct property *prop;
struct ion_platform_heap *p_data;
const struct device_node *dt_node = pdev->dev.of_node;
int index = 0;
for_each_child_of_node(dt_node, np)
num_heaps++;
heaps_data = devm_kzalloc(&pdev->dev,
sizeof(struct ion_platform_heap *) *
num_heaps,
GFP_KERNEL);
if (!heaps_data)
return -ENOMEM;
for_each_child_of_node(dt_node, np) {
ret = of_property_read_string(np, "status", &status);
if (!ret) {
if (strncmp("ok", status, strlen("ok")))
continue;
}
phandle_node = of_parse_phandle(np, "heap-name", 0);
if (phandle_node) {
int len;
ret = of_property_read_string(phandle_node, "status", &status);
if (!ret) {
if (strncmp("ok", status, strlen("ok")))
continue;
}
prop = of_find_property(phandle_node, "heap-name", &len);
if (!prop) {
pr_err("no heap-name in phandle of node %s\n", np->name);
continue;
}
if (!prop->value || !prop->length) {
pr_err("%s %s %d, node %s, invalid phandle, value=%p,length=%d\n",
__FILE__,__FUNCTION__,__LINE__,
np->name, prop->value, prop->length );
continue;
} else {
heap_name = prop->value;
}
} else {
ret = of_property_read_string(np, "heap-name", &heap_name);
if (ret < 0) {
pr_err("invalid heap-name in node %s, please check the name \n", np->name);
continue;
}
}
pr_err("node name [%s], heap-name [%s]\n", np->name, heap_name);
ret = of_property_read_u32(np, "heap-id", &id);
if (ret < 0) {
pr_err("check the id %s\n", np->name);
continue;
}
ret = of_property_read_u32(np, "heap-base", &base);
if (ret < 0) {
pr_err("check the base of node %s\n", np->name);
continue;
}
ret = of_property_read_u32(np, "heap-size", &size);
if (ret < 0) {
pr_err("check the size of node %s\n", np->name);
continue;
}
ret = of_property_read_string(np, "heap-type", &type_name);
if (ret < 0) {
pr_err("check the type of node %s\n", np->name);
continue;
}
ret = get_type_by_name(type_name, &type);
if (ret < 0) {
pr_err("type name error %s!\n", type_name);
continue;
}
pr_err("heap index %d : name %s base 0x%x size 0x%x id %d type %d\n",
index, heap_name, base, size, id, type);
p_data = devm_kzalloc(&pdev->dev,
sizeof(struct ion_platform_heap),
GFP_KERNEL);
if (!p_data)
return -ENOMEM;
p_data->name = heap_name;
p_data->base = base;
p_data->size = size;
p_data->id = id;
p_data->type = type;
p_data->priv = (void *)&pdev->dev;
if (!p_data->base && !p_data->size) {
struct hisi_ion_dynamic_area* area = NULL;
pr_err("heap %s base =0, try to find dynamic area \n", p_data->name);
area = find_dynamic_area_by_name(p_data->name);
if (area) {
p_data->base = area->base;
p_data->size = area->size;
pr_err("have found heap name %s base = 0x%lx, size %zu\n",
p_data->name,
p_data->base, p_data->size);
}
}
heaps_data[index] = p_data;
index++;
}
num_heaps = index;
return 0;
}
static int hisi_ion_probe(struct platform_device *pdev)
{
int i;
int err;
static struct ion_platform_heap *p_heap;
idev = ion_device_create(hisi_ion_custom_ioctl);
err = hisi_set_platform_data(pdev);
if (err) {
pr_err("ion set platform data error!\n");
goto err_free_idev;
}
heaps = devm_kzalloc(&pdev->dev,
sizeof(struct ion_heap *) * num_heaps,
GFP_KERNEL);
if (!heaps) {
err = -ENOMEM;
goto err_free_idev;
}
/* FIXME will move to iommu driver*/
if (hisi_ion_enable_iommu(pdev)) {
dev_info(&pdev->dev, "enable iommu fail \n");
err = -EINVAL;
goto err_free_idev;
}
ion_pm_init();
/*
* create the heaps as specified in the dts file
*/
for (i = 0; i < num_heaps; i++) {
p_heap = heaps_data[i];
pr_info("id %d name %s base %lu size %lu\n",
i, p_heap->name, p_heap->base, p_heap->size);
heaps[i] = ion_heap_create(p_heap);
if (IS_ERR_OR_NULL(heaps[i])) {
pr_err("error add %s of type %d with %lx@%lx\n",
p_heap->name, p_heap->type,
p_heap->base, (unsigned long)p_heap->size);
continue;
}
ion_device_add_heap(idev, heaps[i]);
pr_info("adding heap %s of type %d with %lx@%lx\n",
p_heap->name, p_heap->type,
p_heap->base, (unsigned long)p_heap->size);
}
return 0;
err_free_idev:
ion_device_destroy(idev);
return err;
}
static int hisi_ion_remove(struct platform_device *pdev)
{
int i;
for (i = 0; i < num_heaps; i++) {
ion_heap_destroy(heaps[i]);
heaps[i] = NULL;
}
ion_device_destroy(idev);
return 0;
}
static const struct of_device_id hisi_ion_match_table[] = {
{.compatible = "hisilicon,hisi-ion"},
{},
};
static struct platform_driver hisi_ion_driver = {
.probe = hisi_ion_probe,
.remove = hisi_ion_remove,
.driver = {
.name = "ion-hisi",
.of_match_table = hisi_ion_match_table,
},
};
static int __init hisi_ion_init(void)
{
int ret;
ret = platform_driver_register(&hisi_ion_driver);
return ret;
}
subsys_initcall(hisi_ion_init);
@@ -1,5 +0,0 @@
config HI6220_ION
bool "Hi6220 ION Driver"
depends on ARCH_HISI && ION
help
Build the Hisilicon Hi6220 ion driver.
@@ -1 +1,2 @@
obj-$(CONFIG_HI6220_ION) += hi6220_ion.o
ccflags-y += -I$(srctree)/drivers/staging/android
obj-y += hisi_ion.o
@@ -1,113 +0,0 @@
/*
* Hisilicon Hi6220 ION Driver
*
* Copyright (c) 2015 Hisilicon Limited.
*
* Author: Chen Feng <puck.chen@hisilicon.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define pr_fmt(fmt) "Ion: " fmt
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/mm.h>
#include "../ion_priv.h"
#include "../ion.h"
#include "../ion_of.h"
struct hisi_ion_dev {
struct ion_heap **heaps;
struct ion_device *idev;
struct ion_platform_data *data;
};
static struct ion_of_heap hisi_heaps[] = {
PLATFORM_HEAP("hisilicon,sys_user", 0,
ION_HEAP_TYPE_SYSTEM, "sys_user"),
PLATFORM_HEAP("hisilicon,sys_contig", 1,
ION_HEAP_TYPE_SYSTEM_CONTIG, "sys_contig"),
PLATFORM_HEAP("hisilicon,cma", ION_HEAP_TYPE_DMA, ION_HEAP_TYPE_DMA,
"cma"),
{}
};
static int hi6220_ion_probe(struct platform_device *pdev)
{
struct hisi_ion_dev *ipdev;
int i;
ipdev = devm_kzalloc(&pdev->dev, sizeof(*ipdev), GFP_KERNEL);
if (!ipdev)
return -ENOMEM;
platform_set_drvdata(pdev, ipdev);
ipdev->idev = ion_device_create(NULL);
if (IS_ERR(ipdev->idev))
return PTR_ERR(ipdev->idev);
ipdev->data = ion_parse_dt(pdev, hisi_heaps);
if (IS_ERR(ipdev->data))
return PTR_ERR(ipdev->data);
ipdev->heaps = devm_kzalloc(&pdev->dev,
sizeof(struct ion_heap) * ipdev->data->nr,
GFP_KERNEL);
if (!ipdev->heaps) {
ion_destroy_platform_data(ipdev->data);
return -ENOMEM;
}
for (i = 0; i < ipdev->data->nr; i++) {
ipdev->heaps[i] = ion_heap_create(&ipdev->data->heaps[i]);
if (!ipdev->heaps) {
ion_destroy_platform_data(ipdev->data);
return -ENOMEM;
}
ion_device_add_heap(ipdev->idev, ipdev->heaps[i]);
}
return 0;
}
static int hi6220_ion_remove(struct platform_device *pdev)
{
struct hisi_ion_dev *ipdev;
int i;
ipdev = platform_get_drvdata(pdev);
for (i = 0; i < ipdev->data->nr; i++)
ion_heap_destroy(ipdev->heaps[i]);
ion_destroy_platform_data(ipdev->data);
ion_device_destroy(ipdev->idev);
return 0;
}
static const struct of_device_id hi6220_ion_match_table[] = {
{.compatible = "hisilicon,hi6220-ion"},
{},
};
static struct platform_driver hi6220_ion_driver = {
.probe = hi6220_ion_probe,
.remove = hi6220_ion_remove,
.driver = {
.name = "ion-hi6220",
.of_match_table = hi6220_ion_match_table,
},
};
static int __init hi6220_ion_init(void)
{
return platform_driver_register(&hi6220_ion_driver);
}
subsys_initcall(hi6220_ion_init);
@@ -0,0 +1,266 @@
/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#define pr_fmt(fmt) "ion: " fmt
#include <linux/module.h>
#include <linux/err.h>
#include <linux/hisi_ion.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/dma-mapping.h>
#include "../ion_priv.h"
struct hisi_ion_name_id_table {
const char *name;
unsigned int id;
};
static struct hisi_ion_name_id_table name_id_table[] = {
{"fb", ION_FB_HEAP_ID},
{"vpu", ION_VPU_HEAP_ID},
{"jpu", ION_JPU_HEAP_ID},
{"gralloc-carveout", ION_GRALLOC_HEAP_ID},
{"overlay", ION_OVERLAY_HEAP_ID},
{"sys_user", ION_SYSTEM_HEAP_ID},
{"sys_contig", ION_SYSTEM_CONTIG_HEAP_ID},
{"cma", ION_HEAP_TYPE_DMA},
};
struct hisi_ion_type_id_table {
const char *name;
enum ion_heap_type type;
};
static struct hisi_ion_type_id_table type_id_table[] = {
{"ion_system_contig", ION_HEAP_TYPE_SYSTEM_CONTIG},
{"ion_system", ION_HEAP_TYPE_SYSTEM},
{"ion_carveout", ION_HEAP_TYPE_CARVEOUT},
{"ion_chunk", ION_HEAP_TYPE_CHUNK},
{"ion_dma", ION_HEAP_TYPE_DMA},
{"ion_custom", ION_HEAP_TYPE_CUSTOM},
{"ion_cma", ION_HEAP_TYPE_DMA},
};
#define HISI_ION_HEAP_NUM 16
static struct ion_platform_data hisi_ion_platform_data = {0};
static struct ion_platform_heap hisi_ion_platform_heap[HISI_ION_HEAP_NUM] = {{0} };
static struct ion_device *hisi_ion_device;
static struct ion_heap *hisi_ion_heap[HISI_ION_HEAP_NUM] = {NULL};
int hisi_ion_get_heap_info(unsigned int id, struct ion_heap_info_data *data)
{
int i;
BUG_ON(!data);
for (i = 0; i < hisi_ion_platform_data.nr; i++) {
if (hisi_ion_platform_heap[i].id == id) {
data->heap_phy = hisi_ion_platform_heap[i].base;
data->heap_size = hisi_ion_platform_heap[i].size;
strncpy((void *)data->name, (void *)hisi_ion_platform_heap[i].name, HISI_ION_NAME_LEN);
pr_info("heap info : id %d name %s phy 0x%llx size %u\n",
id, data->name, data->heap_phy, data->heap_size);
return 0;
}
}
pr_err("in %s please check the id %d\n", __func__, id);
return -EINVAL;
}
EXPORT_SYMBOL(hisi_ion_get_heap_info);
struct ion_device *get_ion_device(void)
{
return hisi_ion_device;
}
EXPORT_SYMBOL(get_ion_device);
static int get_id_by_name(const char *name, unsigned int *id)
{
int i, n;
n = sizeof(name_id_table)/sizeof(name_id_table[0]);
for (i = 0; i < n; i++) {
if (strncmp(name, name_id_table[i].name, HISI_ION_NAME_LEN))
continue;
*id = name_id_table[i].id;
return 0;
}
return -1;
}
static int get_type_by_name(const char *name, enum ion_heap_type *type)
{
int i, n;
n = sizeof(type_id_table)/sizeof(type_id_table[0]);
for (i = 0; i < n; i++) {
if (strncmp(name, type_id_table[i].name, HISI_ION_NAME_LEN))
continue;
*type = type_id_table[i].type;
return 0;
}
return -1;
}
static u64 hisi_dmamask = DMA_BIT_MASK(32);
static struct platform_device ion_cma_device = {
.name = "ion-cma-device",
.id = -1,
.dev = {
.dma_mask = &hisi_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
static int hisi_ion_setup_platform_data(struct platform_device *dev)
{
struct device_node *node, *np;
const char *heap_name;
const char *type_name;
unsigned int id;
unsigned int range[2] = {0, 0};
enum ion_heap_type type;
int ret;
int index = 0;
node = dev->dev.of_node;
for_each_child_of_node(node, np) {
ret = of_property_read_string(np, "heap-name", &heap_name);
if (ret < 0) {
pr_err("in node %s please check the name property of node %s\n", __func__, np->name);
continue;
}
ret = get_id_by_name(heap_name, &id);
if (ret < 0) {
pr_err("in node %s please check the name %s\n", __func__, heap_name);
continue;
}
ret = of_property_read_u32_array(np, "heap-range", range, ARRAY_SIZE(range));
if (ret < 0) {
pr_err("in node %s please check the range property of node %s\n", __func__, np->name);
continue;
}
ret = of_property_read_string(np, "heap-type", &type_name);
if (ret < 0) {
pr_err("in node %s please check the type property of node %s\n", __func__, np->name);
continue;
}
ret = get_type_by_name(type_name, &type);
if (ret < 0) {
pr_err("in node %s please check the type %s\n", __func__, type_name);
continue;
}
hisi_ion_platform_heap[index].name = heap_name;
hisi_ion_platform_heap[index].base = range[0];
hisi_ion_platform_heap[index].size = range[1];
hisi_ion_platform_heap[index].id = id;
hisi_ion_platform_heap[index].type = type;
if (type == ION_HEAP_TYPE_DMA) {
// ion_cma_device.dev.archdata.dma_ops = swiotlb_dma_ops;
hisi_ion_platform_heap[index].priv =
(void *)&ion_cma_device.dev;
}
index++;
}
hisi_ion_platform_data.nr = index;
hisi_ion_platform_data.heaps = hisi_ion_platform_heap;
return 0;
}
static int hisi_ion_probe(struct platform_device *pdev)
{
int i, err;
struct ion_heap *heap;
struct ion_platform_heap *heap_data;
if (hisi_ion_setup_platform_data(pdev)) {
pr_err("hisi_ion_setup_platform_data is failed\n");
return -EINVAL;
}
hisi_ion_device = ion_device_create(NULL);
if (IS_ERR_OR_NULL(hisi_ion_device))
return PTR_ERR(hisi_ion_device);
/*
* create the heaps as specified in the board file
*/
for (i = 0; i < hisi_ion_platform_data.nr; i++) {
heap_data = &hisi_ion_platform_data.heaps[i];
heap = ion_heap_create(heap_data);
if (IS_ERR_OR_NULL(heap)) {
err = PTR_ERR(heap);
goto out;
}
ion_device_add_heap(hisi_ion_device, heap);
hisi_ion_heap[i] = heap;
}
platform_set_drvdata(pdev, hisi_ion_device);
return 0;
out:
for (i = 0; i < HISI_ION_HEAP_NUM; i++) {
if (!hisi_ion_heap[i])
continue;
ion_heap_destroy(hisi_ion_heap[i]);
hisi_ion_heap[i] = NULL;
}
return err;
}
static int hisi_ion_remove(struct platform_device *pdev)
{
int i;
ion_device_destroy(hisi_ion_device);
for (i = 0; i < HISI_ION_HEAP_NUM; i++) {
if (!hisi_ion_heap[i])
continue;
ion_heap_destroy(hisi_ion_heap[i]);
hisi_ion_heap[i] = NULL;
}
return 0;
}
static struct of_device_id hisi_ion_match_table[] = {
{.compatible = "hisilicon,ion"},
{},
};
static struct platform_driver hisi_ion_driver = {
.probe = hisi_ion_probe,
.remove = hisi_ion_remove,
.driver = {
.name = "ion",
.of_match_table = hisi_ion_match_table,
},
};
module_platform_driver(hisi_ion_driver);
-177
View File
@@ -1,177 +0,0 @@
/*
*
* 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/kernel.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "ion.h"
#include "ion_priv.h"
#include "compat_ion.h"
union ion_ioctl_arg {
struct ion_fd_data fd;
struct ion_allocation_data allocation;
struct ion_handle_data handle;
struct ion_custom_data custom;
struct ion_heap_query query;
};
static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg)
{
int ret = 0;
switch (cmd) {
case ION_IOC_HEAP_QUERY:
ret = arg->query.reserved0 != 0;
ret |= arg->query.reserved1 != 0;
ret |= arg->query.reserved2 != 0;
break;
default:
break;
}
return ret ? -EINVAL : 0;
}
/* fix up the cases where the ioctl direction bits are incorrect */
static unsigned int ion_ioctl_dir(unsigned int cmd)
{
switch (cmd) {
case ION_IOC_SYNC:
case ION_IOC_FREE:
case ION_IOC_CUSTOM:
return _IOC_WRITE;
default:
return _IOC_DIR(cmd);
}
}
long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct ion_client *client = filp->private_data;
struct ion_device *dev = client->dev;
struct ion_handle *cleanup_handle = NULL;
int ret = 0;
unsigned int dir;
union ion_ioctl_arg data;
dir = ion_ioctl_dir(cmd);
if (_IOC_SIZE(cmd) > sizeof(data))
return -EINVAL;
/*
* The copy_from_user is unconditional here for both read and write
* to do the validate. If there is no write for the ioctl, the
* buffer is cleared
*/
if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
return -EFAULT;
ret = validate_ioctl_arg(cmd, &data);
if (WARN_ON_ONCE(ret))
return ret;
if (!(dir & _IOC_WRITE))
memset(&data, 0, sizeof(data));
switch (cmd) {
case ION_IOC_ALLOC:
{
struct ion_handle *handle;
handle = ion_alloc(client, data.allocation.len,
data.allocation.align,
data.allocation.heap_id_mask,
data.allocation.flags);
if (IS_ERR(handle))
return PTR_ERR(handle);
data.allocation.handle = handle->id;
cleanup_handle = handle;
break;
}
case ION_IOC_FREE:
{
struct ion_handle *handle;
mutex_lock(&client->lock);
handle = ion_handle_get_by_id_nolock(client, data.handle.handle);
if (IS_ERR(handle)) {
mutex_unlock(&client->lock);
return PTR_ERR(handle);
}
ion_free_nolock(client, handle);
ion_handle_put_nolock(handle);
mutex_unlock(&client->lock);
break;
}
case ION_IOC_SHARE:
case ION_IOC_MAP:
{
struct ion_handle *handle;
handle = ion_handle_get_by_id(client, data.handle.handle);
if (IS_ERR(handle))
return PTR_ERR(handle);
data.fd.fd = ion_share_dma_buf_fd(client, handle);
ion_handle_put(handle);
if (data.fd.fd < 0)
ret = data.fd.fd;
break;
}
case ION_IOC_IMPORT:
{
struct ion_handle *handle;
handle = ion_import_dma_buf_fd(client, data.fd.fd);
if (IS_ERR(handle))
ret = PTR_ERR(handle);
else
data.handle.handle = handle->id;
break;
}
case ION_IOC_SYNC:
{
ret = ion_sync_for_device(client, data.fd.fd);
break;
}
case ION_IOC_CUSTOM:
{
if (!dev->custom_ioctl)
return -ENOTTY;
ret = dev->custom_ioctl(client, data.custom.cmd,
data.custom.arg);
break;
}
case ION_IOC_HEAP_QUERY:
ret = ion_query_heaps(client, &data.query);
break;
default:
return -ENOTTY;
}
if (dir & _IOC_READ) {
if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) {
if (cleanup_handle)
ion_free(client, cleanup_handle);
return -EFAULT;
}
}
return ret;
}
File diff suppressed because it is too large Load Diff
+66 -12
View File
@@ -72,6 +72,17 @@ struct ion_platform_data {
struct ion_platform_heap *heaps;
};
/**
* ion_reserve() - reserve memory for ion heaps if applicable
* @data: platform data specifying starting physical address and
* size
*
* Calls memblock reserve to set aside memory for heaps that are
* located at specific memory addresses or of specific sizes not
* managed by the kernel
*/
void ion_reserve(struct ion_platform_data *data);
/**
* ion_client_create() - allocate a client and returns it
* @dev: the global ion device
@@ -118,6 +129,36 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
*/
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_sg_table 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_dma - return an sg_table describing a handle
* @client: the client
* @handle: the handle
*
* This function returns the sg_table describing
* a particular ion handle.
*/
struct sg_table *ion_sg_table(struct ion_client *client,
struct ion_handle *handle);
/**
* ion_map_kernel - create mapping for the given handle
* @client: the client
@@ -151,26 +192,39 @@ struct dma_buf *ion_share_dma_buf(struct ion_client *client,
int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle);
/**
* ion_import_dma_buf() - get ion_handle from dma-buf
* ion_map_iommu() - create iommu mapping for the given handle
* @client: the client
* @dmabuf: the dma-buf
*
* Get the ion_buffer associated with the dma-buf and return the ion_handle.
* If no ion_handle exists for this buffer, return newly created ion_handle.
* If dma-buf from another exporter is passed, return ERR_PTR(-EINVAL)
* @handle: the handle
* @format: the format of iommu mapping
*/
struct ion_handle *ion_import_dma_buf(struct ion_client *client,
struct dma_buf *dmabuf);
int ion_map_iommu(struct ion_client *client, struct ion_handle *handle,
struct iommu_map_format *format);
/**
* ion_import_dma_buf_fd() - given a dma-buf fd from the ion exporter get handle
* ion_unmap_iommu() - destroy a iommu mapping for a handle
* @client: the client
* @handle: the handle
*/
void ion_unmap_iommu(struct ion_client *client, struct ion_handle *handle);
/**
* ion_change_flags() - change buffer flags
* @client: the client
* @handle: the handle
* @flags: flags
*/
int ion_change_flags(struct ion_client *client,
struct ion_handle *handle, int flags);
/**
* ion_import_dma_buf() - given an dma-buf fd from the ion exporter get handle
* @client: the client
* @fd: the dma-buf fd
*
* Given an dma-buf fd that was allocated through ion via ion_share_dma_buf_fd,
* import that fd and return a handle representing it. If a dma-buf from
* Given an dma-buf fd that was allocated through ion via ion_share_dma_buf,
* import that fd and return a handle representing it. If a dma-buf from
* another exporter is passed in this function will return ERR_PTR(-EINVAL)
*/
struct ion_handle *ion_import_dma_buf_fd(struct ion_client *client, int fd);
struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd);
#endif /* _LINUX_ION_H */
+39 -12
View File
@@ -25,17 +25,15 @@
#include "ion.h"
#include "ion_priv.h"
#define ION_CARVEOUT_ALLOCATE_FAIL -1
struct ion_carveout_heap {
struct ion_heap heap;
struct gen_pool *pool;
ion_phys_addr_t base;
};
static ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
unsigned long size,
unsigned long align)
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);
@@ -47,8 +45,8 @@ static ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
return offset;
}
static void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
unsigned long size)
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);
@@ -58,6 +56,19 @@ static void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
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)
{
struct sg_table *table = buffer->priv_virt;
struct page *page = sg_page(table->sgl);
ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));
*addr = paddr;
*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,
@@ -70,7 +81,7 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap,
if (align > PAGE_SIZE)
return -EINVAL;
table = kmalloc(sizeof(*table), GFP_KERNEL);
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table)
return -ENOMEM;
ret = sg_alloc_table(table, 1, GFP_KERNEL);
@@ -84,7 +95,7 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap,
}
sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0);
buffer->sg_table = table;
buffer->priv_virt = table;
return 0;
@@ -98,7 +109,7 @@ err_free:
static void ion_carveout_heap_free(struct ion_buffer *buffer)
{
struct ion_heap *heap = buffer->heap;
struct sg_table *table = buffer->sg_table;
struct sg_table *table = buffer->priv_virt;
struct page *page = sg_page(table->sgl);
ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));
@@ -106,19 +117,35 @@ static void ion_carveout_heap_free(struct ion_buffer *buffer)
if (ion_buffer_cached(buffer))
dma_sync_sg_for_device(NULL, table->sgl, table->nents,
DMA_BIDIRECTIONAL);
DMA_BIDIRECTIONAL);
ion_carveout_free(heap, paddr, buffer->size);
sg_free_table(table);
kfree(table);
}
static struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return buffer->priv_virt;
}
static void ion_carveout_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
}
static struct ion_heap_ops carveout_heap_ops = {
.allocate = ion_carveout_heap_allocate,
.free = ion_carveout_heap_free,
.phys = ion_carveout_heap_phys,
.map_dma = ion_carveout_heap_map_dma,
.unmap_dma = ion_carveout_heap_unmap_dma,
.map_user = ion_heap_map_user,
.map_kernel = ion_heap_map_kernel,
.unmap_kernel = ion_heap_unmap_kernel,
.map_iommu = ion_heap_map_iommu,
.unmap_iommu = ion_heap_unmap_iommu,
};
struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
@@ -138,7 +165,7 @@ struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
if (ret)
return ERR_PTR(ret);
carveout_heap = kzalloc(sizeof(*carveout_heap), GFP_KERNEL);
carveout_heap = kzalloc(sizeof(struct ion_carveout_heap), GFP_KERNEL);
if (!carveout_heap)
return ERR_PTR(-ENOMEM);
+23 -10
View File
@@ -34,9 +34,9 @@ struct ion_chunk_heap {
};
static int ion_chunk_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long size, unsigned long align,
unsigned long flags)
struct ion_buffer *buffer,
unsigned long size, unsigned long align,
unsigned long flags)
{
struct ion_chunk_heap *chunk_heap =
container_of(heap, struct ion_chunk_heap, heap);
@@ -55,7 +55,7 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap,
if (allocated_size > chunk_heap->size - chunk_heap->allocated)
return -ENOMEM;
table = kmalloc(sizeof(*table), GFP_KERNEL);
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table)
return -ENOMEM;
ret = sg_alloc_table(table, num_chunks, GFP_KERNEL);
@@ -71,11 +71,11 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap,
if (!paddr)
goto err;
sg_set_page(sg, pfn_to_page(PFN_DOWN(paddr)),
chunk_heap->chunk_size, 0);
chunk_heap->chunk_size, 0);
sg = sg_next(sg);
}
buffer->sg_table = table;
buffer->priv_virt = table;
chunk_heap->allocated += allocated_size;
return 0;
err:
@@ -95,7 +95,7 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer)
struct ion_heap *heap = buffer->heap;
struct ion_chunk_heap *chunk_heap =
container_of(heap, struct ion_chunk_heap, heap);
struct sg_table *table = buffer->sg_table;
struct sg_table *table = buffer->priv_virt;
struct scatterlist *sg;
int i;
unsigned long allocated_size;
@@ -106,7 +106,7 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer)
if (ion_buffer_cached(buffer))
dma_sync_sg_for_device(NULL, table->sgl, table->nents,
DMA_BIDIRECTIONAL);
DMA_BIDIRECTIONAL);
for_each_sg(table->sgl, sg, table->nents, i) {
gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
@@ -117,9 +117,22 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer)
kfree(table);
}
static struct sg_table *ion_chunk_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return buffer->priv_virt;
}
static void ion_chunk_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
}
static struct ion_heap_ops chunk_heap_ops = {
.allocate = ion_chunk_heap_allocate,
.free = ion_chunk_heap_free,
.map_dma = ion_chunk_heap_map_dma,
.unmap_dma = ion_chunk_heap_unmap_dma,
.map_user = ion_heap_map_user,
.map_kernel = ion_heap_map_kernel,
.unmap_kernel = ion_heap_unmap_kernel,
@@ -141,7 +154,7 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
if (ret)
return ERR_PTR(ret);
chunk_heap = kzalloc(sizeof(*chunk_heap), GFP_KERNEL);
chunk_heap = kzalloc(sizeof(struct ion_chunk_heap), GFP_KERNEL);
if (!chunk_heap)
return ERR_PTR(-ENOMEM);
@@ -161,7 +174,7 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK;
chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
pr_debug("%s: base %lu size %zu align %ld\n", __func__,
chunk_heap->base, heap_data->size, heap_data->align);
chunk_heap->base, heap_data->size, heap_data->align);
return &chunk_heap->heap;
+36 -2
View File
@@ -78,7 +78,6 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
goto free_table;
/* keep this for memory release */
buffer->priv_virt = info;
buffer->sg_table = info->table;
dev_dbg(dev, "Allocate buffer %p\n", buffer);
return 0;
@@ -106,6 +105,36 @@ static void ion_cma_free(struct ion_buffer *buffer)
kfree(info);
}
/* return physical address in addr */
static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len)
{
struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap);
struct device *dev = cma_heap->dev;
struct ion_cma_buffer_info *info = buffer->priv_virt;
dev_dbg(dev, "Return buffer %p physical address %pa\n", buffer,
&info->handle);
*addr = info->handle;
*len = buffer->size;
return 0;
}
static struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
struct ion_cma_buffer_info *info = buffer->priv_virt;
return info->table;
}
static void ion_cma_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
}
static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer,
struct vm_area_struct *vma)
{
@@ -126,16 +155,21 @@ static void *ion_cma_map_kernel(struct ion_heap *heap,
}
static void ion_cma_unmap_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
struct ion_buffer *buffer)
{
}
static struct ion_heap_ops ion_cma_ops = {
.allocate = ion_cma_allocate,
.free = ion_cma_free,
.map_dma = ion_cma_heap_map_dma,
.unmap_dma = ion_cma_heap_unmap_dma,
.phys = ion_cma_phys,
.map_user = ion_cma_mmap,
.map_kernel = ion_cma_map_kernel,
.unmap_kernel = ion_cma_unmap_kernel,
.map_iommu = ion_heap_map_iommu,
.unmap_iommu = ion_heap_unmap_iommu,
};
struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data)
@@ -68,8 +68,6 @@ static int __init ion_dummy_init(void)
int i, err;
idev = ion_device_create(NULL);
if (IS_ERR(idev))
return PTR_ERR(idev);
heaps = kcalloc(dummy_ion_pdata.nr, sizeof(struct ion_heap *),
GFP_KERNEL);
if (!heaps)
@@ -99,7 +97,7 @@ static int __init ion_dummy_init(void)
struct ion_platform_heap *heap_data = &dummy_ion_pdata.heaps[i];
if (heap_data->type == ION_HEAP_TYPE_CARVEOUT &&
!heap_data->base)
!heap_data->base)
continue;
if (heap_data->type == ION_HEAP_TYPE_CHUNK && !heap_data->base)
@@ -120,12 +118,12 @@ err:
if (carveout_ptr) {
free_pages_exact(carveout_ptr,
dummy_heaps[ION_HEAP_TYPE_CARVEOUT].size);
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);
dummy_heaps[ION_HEAP_TYPE_CHUNK].size);
chunk_ptr = NULL;
}
return err;
@@ -144,12 +142,12 @@ static void __exit ion_dummy_exit(void)
if (carveout_ptr) {
free_pages_exact(carveout_ptr,
dummy_heaps[ION_HEAP_TYPE_CARVEOUT].size);
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);
dummy_heaps[ION_HEAP_TYPE_CHUNK].size);
chunk_ptr = NULL;
}
}
+33 -5
View File
@@ -22,6 +22,9 @@
#include <linux/sched.h>
#include <linux/scatterlist.h>
#include <linux/vmalloc.h>
#include <linux/iommu.h>
#include <linux/hisi/ion-iommu.h>
#include "ion.h"
#include "ion_priv.h"
@@ -93,7 +96,7 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
}
len = min(len, remainder);
ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
vma->vm_page_prot);
vma->vm_page_prot);
if (ret)
return ret;
addr += len;
@@ -103,6 +106,31 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
return 0;
}
int ion_heap_map_iommu(struct ion_buffer *buffer,
struct ion_iommu_map *map_data)
{
struct sg_table *table = buffer->sg_table;
int ret;
ret = hisi_iommu_map_domain(table->sgl, &map_data->format);
if (ret) {
pr_err("%s: iommu map failed, heap: %s\n", __func__,
buffer->heap->name);
}
return ret;
}
void ion_heap_unmap_iommu(struct ion_iommu_map *map_data)
{
int ret;
ret = hisi_iommu_unmap_domain(&map_data->format);
if (ret) {
pr_err("%s: iommu unmap failed, heap: %s\n", __func__,
map_data->buffer->heap->name);
}
}
static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot)
{
void *addr = vm_map_ram(pages, num, -1, pgprot);
@@ -116,7 +144,7 @@ static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot)
}
static int ion_heap_sglist_zero(struct scatterlist *sgl, unsigned int nents,
pgprot_t pgprot)
pgprot_t pgprot)
{
int p = 0;
int ret = 0;
@@ -181,7 +209,7 @@ size_t ion_heap_freelist_size(struct ion_heap *heap)
}
static size_t _ion_heap_freelist_drain(struct ion_heap *heap, size_t size,
bool skip_pools)
bool skip_pools)
{
struct ion_buffer *buffer;
size_t total_drained = 0;
@@ -266,7 +294,7 @@ int ion_heap_init_deferred_free(struct ion_heap *heap)
}
static unsigned long ion_heap_shrink_count(struct shrinker *shrinker,
struct shrink_control *sc)
struct shrink_control *sc)
{
struct ion_heap *heap = container_of(shrinker, struct ion_heap,
shrinker);
@@ -279,7 +307,7 @@ static unsigned long ion_heap_shrink_count(struct shrinker *shrinker,
}
static unsigned long ion_heap_shrink_scan(struct shrinker *shrinker,
struct shrink_control *sc)
struct shrink_control *sc)
{
struct ion_heap *heap = container_of(shrinker, struct ion_heap,
shrinker);
-185
View File
@@ -1,185 +0,0 @@
/*
* Based on work from:
* Andrew Andrianov <andrew@ncrmnt.org>
* Google
* The Linux Foundation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/cma.h>
#include <linux/dma-contiguous.h>
#include <linux/io.h>
#include <linux/of_reserved_mem.h>
#include "ion.h"
#include "ion_priv.h"
#include "ion_of.h"
static int ion_parse_dt_heap_common(struct device_node *heap_node,
struct ion_platform_heap *heap,
struct ion_of_heap *compatible)
{
int i;
for (i = 0; compatible[i].name; i++) {
if (of_device_is_compatible(heap_node, compatible[i].compat))
break;
}
if (!compatible[i].name)
return -ENODEV;
heap->id = compatible[i].heap_id;
heap->type = compatible[i].type;
heap->name = compatible[i].name;
heap->align = compatible[i].align;
/* Some kind of callback function pointer? */
pr_info("%s: id %d type %d name %s align %lx\n", __func__,
heap->id, heap->type, heap->name, heap->align);
return 0;
}
static int ion_setup_heap_common(struct platform_device *parent,
struct device_node *heap_node,
struct ion_platform_heap *heap)
{
int ret = 0;
switch (heap->type) {
case ION_HEAP_TYPE_CARVEOUT:
case ION_HEAP_TYPE_CHUNK:
if (heap->base && heap->size)
return 0;
ret = of_reserved_mem_device_init(heap->priv);
break;
default:
break;
}
return ret;
}
struct ion_platform_data *ion_parse_dt(struct platform_device *pdev,
struct ion_of_heap *compatible)
{
int num_heaps, ret;
const struct device_node *dt_node = pdev->dev.of_node;
struct device_node *node;
struct ion_platform_heap *heaps;
struct ion_platform_data *data;
int i = 0;
num_heaps = of_get_available_child_count(dt_node);
if (!num_heaps)
return ERR_PTR(-EINVAL);
heaps = devm_kzalloc(&pdev->dev,
sizeof(struct ion_platform_heap) * num_heaps,
GFP_KERNEL);
if (!heaps)
return ERR_PTR(-ENOMEM);
data = devm_kzalloc(&pdev->dev, sizeof(struct ion_platform_data),
GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
for_each_available_child_of_node(dt_node, node) {
struct platform_device *heap_pdev;
ret = ion_parse_dt_heap_common(node, &heaps[i], compatible);
if (ret)
return ERR_PTR(ret);
heap_pdev = of_platform_device_create(node, heaps[i].name,
&pdev->dev);
if (!heap_pdev)
return ERR_PTR(-ENOMEM);
heap_pdev->dev.platform_data = &heaps[i];
heaps[i].priv = &heap_pdev->dev;
ret = ion_setup_heap_common(pdev, node, &heaps[i]);
if (ret)
goto out_err;
i++;
}
data->heaps = heaps;
data->nr = num_heaps;
return data;
out_err:
for ( ; i >= 0; i--)
if (heaps[i].priv)
of_device_unregister(to_platform_device(heaps[i].priv));
return ERR_PTR(ret);
}
void ion_destroy_platform_data(struct ion_platform_data *data)
{
int i;
for (i = 0; i < data->nr; i++)
if (data->heaps[i].priv)
of_device_unregister(to_platform_device(
data->heaps[i].priv));
}
#ifdef CONFIG_OF_RESERVED_MEM
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
static int rmem_ion_device_init(struct reserved_mem *rmem, struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ion_platform_heap *heap = pdev->dev.platform_data;
heap->base = rmem->base;
heap->base = rmem->size;
pr_debug("%s: heap %s base %pa size %pa dev %p\n", __func__,
heap->name, &rmem->base, &rmem->size, dev);
return 0;
}
static void rmem_ion_device_release(struct reserved_mem *rmem,
struct device *dev)
{
return;
}
static const struct reserved_mem_ops rmem_dma_ops = {
.device_init = rmem_ion_device_init,
.device_release = rmem_ion_device_release,
};
static int __init rmem_ion_setup(struct reserved_mem *rmem)
{
phys_addr_t size = rmem->size;
size = size / 1024;
pr_info("Ion memory setup at %pa size %pa MiB\n",
&rmem->base, &size);
rmem->ops = &rmem_dma_ops;
return 0;
}
RESERVEDMEM_OF_DECLARE(ion, "ion-region", rmem_ion_setup);
#endif
-37
View File
@@ -1,37 +0,0 @@
/*
* Based on work from:
* Andrew Andrianov <andrew@ncrmnt.org>
* Google
* The Linux Foundation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ION_OF_H
#define _ION_OF_H
struct ion_of_heap {
const char *compat;
int heap_id;
int type;
const char *name;
int align;
};
#define PLATFORM_HEAP(_compat, _id, _type, _name) \
{ \
.compat = _compat, \
.heap_id = _id, \
.type = _type, \
.name = _name, \
.align = PAGE_SIZE, \
}
struct ion_platform_data *ion_parse_dt(struct platform_device *pdev,
struct ion_of_heap *compatible);
void ion_destroy_platform_data(struct ion_platform_data *data);
#endif
+14 -10
View File
@@ -30,15 +30,17 @@ static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
if (!page)
return NULL;
if (!pool->cached)
ion_pages_sync_for_device(NULL, page, PAGE_SIZE << pool->order,
DMA_BIDIRECTIONAL);
ion_page_pool_alloc_set_cache_policy(pool, page);
ion_pages_sync_for_device(NULL, page, PAGE_SIZE << pool->order,
DMA_BIDIRECTIONAL);
return page;
}
static void ion_page_pool_free_pages(struct ion_page_pool *pool,
struct page *page)
{
ion_page_pool_free_set_cache_policy(pool, page);
__free_pages(page, pool->order);
}
@@ -104,6 +106,11 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
ion_page_pool_free_pages(pool, page);
}
void ion_page_pool_free_immediate(struct ion_page_pool *pool, struct page *page)
{
ion_page_pool_free_pages(pool, page);
}
static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
{
int count = pool->low_count;
@@ -115,7 +122,7 @@ 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_to_scan)
{
int freed = 0;
bool high;
@@ -148,11 +155,10 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
return freed;
}
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
bool cached)
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
{
struct ion_page_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL);
struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool),
GFP_KERNEL);
if (!pool)
return NULL;
pool->high_count = 0;
@@ -163,8 +169,6 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
pool->order = order;
mutex_init(&pool->mutex);
plist_node_init(&pool->list, order);
if (cached)
pool->cached = true;
return pool;
}
+85 -99
View File
@@ -26,10 +26,21 @@
#include <linux/sched.h>
#include <linux/shrinker.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/iommu.h>
#ifdef CONFIG_ION_POOL_CACHE_POLICY
#include <asm/cacheflush.h>
#endif
#include "ion.h"
struct ion_buffer *ion_handle_buffer(struct ion_handle *handle);
struct ion_iommu_map {
struct ion_buffer *buffer;
struct kref ref;
struct iommu_map_format format;
};
/**
* struct ion_buffer - metadata for a particular buffer
* @ref: reference count
@@ -41,6 +52,8 @@
* @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 kernel mapping if kmap_cnt is not zero
@@ -66,7 +79,10 @@ struct ion_buffer {
unsigned long flags;
unsigned long private_flags;
size_t size;
void *priv_virt;
union {
void *priv_virt;
ion_phys_addr_t priv_phys;
};
struct mutex lock;
int kmap_cnt;
void *vaddr;
@@ -78,88 +94,21 @@ struct ion_buffer {
int handle_count;
char task_comm[TASK_COMM_LEN];
pid_t pid;
struct ion_iommu_map *iommu_map;
/*use for sync & free when buffer alloc from cpu draw heap*/
struct sg_table *cpudraw_sg_table;
size_t cpu_buffer_size;
};
void ion_buffer_destroy(struct ion_buffer *buffer);
/**
* struct ion_device - the metadata of the ion device node
* @dev: the actual misc device
* @buffers: an rb tree of all the existing buffers
* @buffer_lock: lock protecting the tree of buffers
* @lock: rwsem protecting the tree of heaps and clients
* @heaps: list of all the heaps in the system
* @user_clients: list of all the clients created from userspace
*/
struct ion_device {
struct miscdevice dev;
struct rb_root buffers;
struct mutex buffer_lock;
struct rw_semaphore lock;
struct plist_head heaps;
long (*custom_ioctl)(struct ion_client *client, unsigned int cmd,
unsigned long arg);
struct rb_root clients;
struct dentry *debug_root;
struct dentry *heaps_debug_root;
struct dentry *clients_debug_root;
int heap_cnt;
};
/**
* struct ion_client - a process/hw block local address space
* @node: node in the tree of all clients
* @dev: backpointer to ion device
* @handles: an rb tree of all the handles in this client
* @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.
* The mutex stored here is used to protect both handles tree
* as well as the handles themselves, and should be held while modifying either.
*/
struct ion_client {
struct rb_node node;
struct ion_device *dev;
struct rb_root handles;
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;
};
/**
* ion_handle - a client local reference to a buffer
* @ref: reference count
* @client: back pointer to the client the buffer resides in
* @buffer: pointer to the buffer
* @node: node in the client's handle rbtree
* @kmap_cnt: count of times this client has mapped to kernel
* @id: client-unique id allocated by client->idr
*
* Modifications to node, map_cnt or mapping should be protected by the
* lock in the client. Other fields are never changed after initialization.
*/
struct ion_handle {
struct kref ref;
struct ion_client *client;
struct ion_buffer *buffer;
struct rb_node node;
unsigned int kmap_cnt;
int id;
};
/**
* 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
@@ -176,10 +125,19 @@ struct ion_heap_ops {
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 sg_table * (*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);
int (*map_iommu)(struct ion_buffer *buffer,
struct ion_iommu_map *map_data);
void (*unmap_iommu)(struct ion_iommu_map *map_data);
void (*buffer_zero)(struct ion_buffer *buffer);
int (*shrink)(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan);
};
@@ -291,6 +249,10 @@ void *ion_heap_map_kernel(struct ion_heap *, struct ion_buffer *);
void ion_heap_unmap_kernel(struct ion_heap *, struct ion_buffer *);
int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
struct vm_area_struct *);
int ion_heap_map_iommu(struct ion_buffer *buffer,
struct ion_iommu_map *map_data);
void ion_heap_unmap_iommu(struct ion_iommu_map *map_data);
void ion_flush_all_cpus_caches(void);
int ion_heap_buffer_zero(struct ion_buffer *buffer);
int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot);
@@ -387,6 +349,20 @@ void ion_chunk_heap_destroy(struct ion_heap *);
struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *);
void ion_cma_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
/**
* functions for creating and destroying a heap pool -- allows you
* to keep a pool of pre allocated memory to use from your heap. Keeping
@@ -406,7 +382,6 @@ void ion_cma_heap_destroy(struct ion_heap *);
* @gfp_mask: gfp_mask to use from alloc
* @order: order of pages in the pool
* @list: plist node for list of pools
* @cached: it's cached pool or not
*
* Allows you to keep a pool of pre allocated pages to use from your heap.
* Keeping a pool of pages that is ready for dma, ie any cached mapping have
@@ -416,7 +391,6 @@ void ion_cma_heap_destroy(struct ion_heap *);
struct ion_page_pool {
int high_count;
int low_count;
bool cached;
struct list_head high_items;
struct list_head low_items;
struct mutex mutex;
@@ -425,11 +399,41 @@ struct ion_page_pool {
struct plist_node list;
};
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
bool cached);
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
void ion_page_pool_destroy(struct ion_page_pool *);
struct page *ion_page_pool_alloc(struct ion_page_pool *);
void ion_page_pool_free(struct ion_page_pool *, struct page *);
void ion_page_pool_free_immediate(struct ion_page_pool *, struct page *);
#ifdef CONFIG_ION_POOL_CACHE_POLICY
static inline void ion_page_pool_alloc_set_cache_policy
(struct ion_page_pool *pool,
struct page *page){
void *va = page_address(page);
if (va)
set_memory_wc((unsigned long)va, 1 << pool->order);
}
static inline void ion_page_pool_free_set_cache_policy
(struct ion_page_pool *pool,
struct page *page){
void *va = page_address(page);
if (va)
set_memory_wb((unsigned long)va, 1 << pool->order);
}
#else
static inline void ion_page_pool_alloc_set_cache_policy
(struct ion_page_pool *pool,
struct page *page){ }
static inline void ion_page_pool_free_set_cache_policy
(struct ion_page_pool *pool,
struct page *page){ }
#endif
/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
* @pool: the pool
@@ -452,22 +456,4 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
void ion_pages_sync_for_device(struct device *dev, struct page *page,
size_t size, enum dma_data_direction dir);
long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
int ion_sync_for_device(struct ion_client *client, int fd);
struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client,
int id);
void ion_free_nolock(struct ion_client *client, struct ion_handle *handle);
int ion_handle_put_nolock(struct ion_handle *handle);
struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
int id);
int ion_handle_put(struct ion_handle *handle);
int ion_query_heaps(struct ion_client *client, struct ion_heap_query *query);
#endif /* _ION_PRIV_H */
+112 -131
View File
@@ -26,18 +26,16 @@
#include "ion.h"
#include "ion_priv.h"
#define NUM_ORDERS ARRAY_SIZE(orders)
static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN |
__GFP_NORETRY) & ~__GFP_RECLAIM;
static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO);
__GFP_NORETRY) & ~__GFP_DIRECT_RECLAIM;
static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN);
static const unsigned int orders[] = {8, 4, 0};
static const int num_orders = ARRAY_SIZE(orders);
static int order_to_index(unsigned int order)
{
int i;
for (i = 0; i < NUM_ORDERS; i++)
for (i = 0; i < num_orders; i++)
if (order == orders[i])
return i;
BUG();
@@ -51,55 +49,49 @@ static inline unsigned int order_to_size(int order)
struct ion_system_heap {
struct ion_heap heap;
struct ion_page_pool *uncached_pools[NUM_ORDERS];
struct ion_page_pool *cached_pools[NUM_ORDERS];
struct ion_page_pool *pools[0];
};
/**
* The page from page-pool are all zeroed before. We need do cache
* clean for cached buffer. The uncached buffer are always non-cached
* since it's allocated. So no need for non-cached pages.
*/
static struct page *alloc_buffer_page(struct ion_system_heap *heap,
struct ion_buffer *buffer,
unsigned long order)
{
bool cached = ion_buffer_cached(buffer);
struct ion_page_pool *pool;
struct ion_page_pool *pool = heap->pools[order_to_index(order)];
struct page *page;
if (!cached)
pool = heap->uncached_pools[order_to_index(order)];
else
pool = heap->cached_pools[order_to_index(order)];
if (!cached) {
page = ion_page_pool_alloc(pool);
} else {
gfp_t gfp_flags = low_order_gfp_flags;
page = ion_page_pool_alloc(pool);
if (cached)
if (order > 4)
gfp_flags = high_order_gfp_flags;
page = alloc_pages(gfp_flags | __GFP_COMP, order);
if (!page)
return NULL;
ion_pages_sync_for_device(NULL, page, PAGE_SIZE << order,
DMA_BIDIRECTIONAL);
DMA_BIDIRECTIONAL);
}
return page;
}
static void free_buffer_page(struct ion_system_heap *heap,
struct ion_buffer *buffer, struct page *page)
{
struct ion_page_pool *pool;
unsigned int order = compound_order(page);
bool cached = ion_buffer_cached(buffer);
/* go to system */
if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE) {
if (!cached) {
struct ion_page_pool *pool = heap->pools[order_to_index(order)];
if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)
ion_page_pool_free_immediate(pool, page);
else
ion_page_pool_free(pool, page);
} else {
__free_pages(page, order);
return;
}
if (!cached)
pool = heap->uncached_pools[order_to_index(order)];
else
pool = heap->cached_pools[order_to_index(order)];
ion_page_pool_free(pool, page);
}
@@ -111,7 +103,7 @@ static struct page *alloc_largest_available(struct ion_system_heap *heap,
struct page *page;
int i;
for (i = 0; i < NUM_ORDERS; i++) {
for (i = 0; i < num_orders; i++) {
if (size < order_to_size(orders[i]))
continue;
if (max_order < orders[i])
@@ -128,9 +120,9 @@ static struct page *alloc_largest_available(struct ion_system_heap *heap,
}
static int ion_system_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long size, unsigned long align,
unsigned long flags)
struct ion_buffer *buffer,
unsigned long size, unsigned long align,
unsigned long flags)
{
struct ion_system_heap *sys_heap = container_of(heap,
struct ion_system_heap,
@@ -152,7 +144,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
INIT_LIST_HEAD(&pages);
while (size_remaining > 0) {
page = alloc_largest_available(sys_heap, buffer, size_remaining,
max_order);
max_order);
if (!page)
goto free_pages;
list_add_tail(&page->lru, &pages);
@@ -174,7 +166,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
list_del(&page->lru);
}
buffer->sg_table = table;
buffer->priv_virt = table;
return 0;
free_table:
@@ -191,11 +183,16 @@ static void ion_system_heap_free(struct ion_buffer *buffer)
struct ion_system_heap,
heap);
struct sg_table *table = buffer->sg_table;
bool cached = ion_buffer_cached(buffer);
struct scatterlist *sg;
int i;
/* zero the buffer before goto page pool */
if (!(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE))
/*
* uncached pages come from the page pools, zero them before returning
* for security purposes (other allocations are zerod at
* alloc time
*/
if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE))
ion_heap_buffer_zero(buffer);
for_each_sg(table->sgl, sg, table->nents, i)
@@ -204,11 +201,20 @@ static void ion_system_heap_free(struct ion_buffer *buffer)
kfree(table);
}
static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
int nr_to_scan)
static struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return buffer->priv_virt;
}
static void ion_system_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
}
static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
int nr_to_scan)
{
struct ion_page_pool *uncached_pool;
struct ion_page_pool *cached_pool;
struct ion_system_heap *sys_heap;
int nr_total = 0;
int i, nr_freed;
@@ -219,44 +225,33 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
if (!nr_to_scan)
only_scan = 1;
for (i = 0; i < NUM_ORDERS; i++) {
uncached_pool = sys_heap->uncached_pools[i];
cached_pool = sys_heap->cached_pools[i];
for (i = 0; i < num_orders; i++) {
struct ion_page_pool *pool = sys_heap->pools[i];
if (only_scan) {
nr_total += ion_page_pool_shrink(uncached_pool,
gfp_mask,
nr_to_scan);
nr_freed = ion_page_pool_shrink(pool, gfp_mask, nr_to_scan);
nr_total += nr_freed;
nr_total += ion_page_pool_shrink(cached_pool,
gfp_mask,
nr_to_scan);
} else {
nr_freed = ion_page_pool_shrink(uncached_pool,
gfp_mask,
nr_to_scan);
if (!only_scan) {
nr_to_scan -= nr_freed;
nr_total += nr_freed;
if (nr_to_scan <= 0)
break;
nr_freed = ion_page_pool_shrink(cached_pool,
gfp_mask,
nr_to_scan);
nr_to_scan -= nr_freed;
nr_total += nr_freed;
/* shrink completed */
if (nr_to_scan <= 0)
break;
}
}
return nr_total;
}
static struct ion_heap_ops system_heap_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_heap_map_kernel,
.unmap_kernel = ion_heap_unmap_kernel,
.map_user = ion_heap_map_user,
.map_iommu = ion_heap_map_iommu,
.unmap_iommu = ion_heap_unmap_iommu,
.shrink = ion_system_heap_shrink,
};
@@ -268,89 +263,52 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
struct ion_system_heap,
heap);
int i;
struct ion_page_pool *pool;
for (i = 0; i < NUM_ORDERS; i++) {
pool = sys_heap->uncached_pools[i];
for (i = 0; i < num_orders; i++) {
struct ion_page_pool *pool = sys_heap->pools[i];
seq_printf(s, "%d order %u highmem pages uncached %lu total\n",
seq_printf(s, "%d order %u highmem pages in pool = %lu total\n",
pool->high_count, pool->order,
(PAGE_SIZE << pool->order) * pool->high_count);
seq_printf(s, "%d order %u lowmem pages uncached %lu total\n",
pool->low_count, pool->order,
(PAGE_SIZE << pool->order) * pool->low_count);
}
for (i = 0; i < NUM_ORDERS; i++) {
pool = sys_heap->cached_pools[i];
seq_printf(s, "%d order %u highmem pages cached %lu total\n",
pool->high_count, pool->order,
(PAGE_SIZE << pool->order) * pool->high_count);
seq_printf(s, "%d order %u lowmem pages cached %lu total\n",
seq_printf(s, "%d order %u lowmem pages in pool = %lu total\n",
pool->low_count, pool->order,
(PAGE_SIZE << pool->order) * pool->low_count);
}
return 0;
}
static void ion_system_heap_destroy_pools(struct ion_page_pool **pools)
{
int i;
for (i = 0; i < NUM_ORDERS; i++)
if (pools[i])
ion_page_pool_destroy(pools[i]);
}
static int ion_system_heap_create_pools(struct ion_page_pool **pools,
bool cached)
{
int i;
gfp_t gfp_flags = low_order_gfp_flags;
for (i = 0; i < NUM_ORDERS; i++) {
struct ion_page_pool *pool;
if (orders[i] > 4)
gfp_flags = high_order_gfp_flags;
pool = ion_page_pool_create(gfp_flags, orders[i], cached);
if (!pool)
goto err_create_pool;
pools[i] = pool;
}
return 0;
err_create_pool:
ion_system_heap_destroy_pools(pools);
return -ENOMEM;
}
struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
{
struct ion_system_heap *heap;
int i;
heap = kzalloc(sizeof(*heap), GFP_KERNEL);
heap = kzalloc(sizeof(struct ion_system_heap) +
sizeof(struct ion_page_pool *) * num_orders,
GFP_KERNEL);
if (!heap)
return ERR_PTR(-ENOMEM);
heap->heap.ops = &system_heap_ops;
heap->heap.type = ION_HEAP_TYPE_SYSTEM;
heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
if (ion_system_heap_create_pools(heap->uncached_pools, false))
goto free_heap;
for (i = 0; i < num_orders; i++) {
struct ion_page_pool *pool;
gfp_t gfp_flags = low_order_gfp_flags;
if (ion_system_heap_create_pools(heap->cached_pools, true))
goto destroy_uncached_pools;
if (orders[i] > 4)
gfp_flags = high_order_gfp_flags;
pool = ion_page_pool_create(gfp_flags, orders[i]);
if (!pool)
goto destroy_pools;
heap->pools[i] = pool;
}
heap->heap.debug_show = ion_system_heap_debug_show;
return &heap->heap;
destroy_uncached_pools:
ion_system_heap_destroy_pools(heap->uncached_pools);
free_heap:
destroy_pools:
while (i--)
ion_page_pool_destroy(heap->pools[i]);
kfree(heap);
return ERR_PTR(-ENOMEM);
}
@@ -362,10 +320,8 @@ void ion_system_heap_destroy(struct ion_heap *heap)
heap);
int i;
for (i = 0; i < NUM_ORDERS; i++) {
ion_page_pool_destroy(sys_heap->uncached_pools[i]);
ion_page_pool_destroy(sys_heap->cached_pools[i]);
}
for (i = 0; i < num_orders; i++)
ion_page_pool_destroy(sys_heap->pools[i]);
kfree(sys_heap);
}
@@ -406,7 +362,7 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap,
sg_set_page(table->sgl, page, len, 0);
buffer->sg_table = table;
buffer->priv_virt = table;
ion_pages_sync_for_device(NULL, page, len, DMA_BIDIRECTIONAL);
@@ -423,7 +379,7 @@ free_pages:
static void ion_system_contig_heap_free(struct ion_buffer *buffer)
{
struct sg_table *table = buffer->sg_table;
struct sg_table *table = buffer->priv_virt;
struct page *page = sg_page(table->sgl);
unsigned long pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT;
unsigned long i;
@@ -434,9 +390,34 @@ static void ion_system_contig_heap_free(struct ion_buffer *buffer)
kfree(table);
}
static int ion_system_contig_heap_phys(struct ion_heap *heap,
struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len)
{
struct sg_table *table = buffer->priv_virt;
struct page *page = sg_page(table->sgl);
*addr = page_to_phys(page);
*len = buffer->size;
return 0;
}
static struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return buffer->priv_virt;
}
static void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
}
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_contig_heap_unmap_dma,
.map_kernel = ion_heap_map_kernel,
.unmap_kernel = ion_heap_unmap_kernel,
.map_user = ion_heap_map_user,
+13 -16
View File
@@ -42,8 +42,7 @@ struct ion_test_data {
};
static int ion_handle_test_dma(struct device *dev, struct dma_buf *dma_buf,
void __user *ptr, size_t offset, size_t size,
bool write)
void __user *ptr, size_t offset, size_t size, bool write)
{
int ret = 0;
struct dma_buf_attachment *attach;
@@ -99,7 +98,7 @@ err:
}
static int ion_handle_test_kernel(struct dma_buf *dma_buf, void __user *ptr,
size_t offset, size_t size, bool write)
size_t offset, size_t size, bool write)
{
int ret;
unsigned long page_offset = offset >> PAGE_SHIFT;
@@ -110,7 +109,7 @@ static int ion_handle_test_kernel(struct dma_buf *dma_buf, void __user *ptr,
if (offset > dma_buf->size || size > dma_buf->size - offset)
return -EINVAL;
ret = dma_buf_begin_cpu_access(dma_buf, dir);
ret = dma_buf_begin_cpu_access(dma_buf, offset, size, dir);
if (ret)
return ret;
@@ -140,12 +139,12 @@ static int ion_handle_test_kernel(struct dma_buf *dma_buf, void __user *ptr,
copy_offset = 0;
}
err:
dma_buf_end_cpu_access(dma_buf, dir);
dma_buf_end_cpu_access(dma_buf, offset, size, dir);
return ret;
}
static long ion_test_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
unsigned long arg)
{
struct ion_test_data *test_data = filp->private_data;
int ret = 0;
@@ -180,19 +179,17 @@ static long ion_test_ioctl(struct file *filp, unsigned int cmd,
case ION_IOC_TEST_DMA_MAPPING:
{
ret = ion_handle_test_dma(test_data->dev, test_data->dma_buf,
u64_to_uptr(data.test_rw.ptr),
data.test_rw.offset,
data.test_rw.size,
data.test_rw.write);
u64_to_uptr(data.test_rw.ptr),
data.test_rw.offset, data.test_rw.size,
data.test_rw.write);
break;
}
case ION_IOC_TEST_KERNEL_MAPPING:
{
ret = ion_handle_test_kernel(test_data->dma_buf,
u64_to_uptr(data.test_rw.ptr),
data.test_rw.offset,
data.test_rw.size,
data.test_rw.write);
u64_to_uptr(data.test_rw.ptr),
data.test_rw.offset, data.test_rw.size,
data.test_rw.write);
break;
}
default:
@@ -211,7 +208,7 @@ static int ion_test_open(struct inode *inode, struct file *file)
struct ion_test_data *data;
struct miscdevice *miscdev = file->private_data;
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = kzalloc(sizeof(struct ion_test_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -245,7 +242,7 @@ static int __init ion_test_probe(struct platform_device *pdev)
struct ion_test_device *testdev;
testdev = devm_kzalloc(&pdev->dev, sizeof(struct ion_test_device),
GFP_KERNEL);
GFP_KERNEL);
if (!testdev)
return -ENOMEM;
@@ -33,11 +33,12 @@ static int tegra_ion_probe(struct platform_device *pdev)
num_heaps = pdata->nr;
heaps = devm_kcalloc(&pdev->dev, pdata->nr,
sizeof(struct ion_heap *), GFP_KERNEL);
heaps = devm_kzalloc(&pdev->dev,
sizeof(struct ion_heap *) * pdata->nr,
GFP_KERNEL);
idev = ion_device_create(NULL);
if (IS_ERR(idev))
if (IS_ERR_OR_NULL(idev))
return PTR_ERR(idev);
/* create the heaps as specified in the board file */
+56 -49
View File
@@ -19,6 +19,7 @@
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/iommu.h>
typedef int ion_user_handle_t;
@@ -40,30 +41,45 @@ enum ion_heap_type {
ION_HEAP_TYPE_CARVEOUT,
ION_HEAP_TYPE_CHUNK,
ION_HEAP_TYPE_DMA,
ION_HEAP_TYPE_CUSTOM, /*
* must be last so device specific heaps always
* are at the end of this enum
*/
ION_HEAP_TYPE_DMA_POOL,
ION_HEAP_TYPE_CPUDRAW,
ION_HEAP_TYPE_IOMMU,
ION_HEAP_TYPE_SECCM,
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
are at the end of this enum */
ION_HEAP_TYPE_RESERVED,
ION_NUM_HEAPS = 16,
};
#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)
#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
#define ION_HEAP_TYPE_DMA_POOL_MASK (1 << ION_HEAP_TYPE_DMA_POOL)
#define ION_HEAP_CPUDRAW_MASK (1 << ION_HEAP_TYPE_CPUDRAW)
#define ION_HEAP_TYPE_IOMMU_MASK (1 << ION_HEAP_TYPE_IOMMU)
#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
/**
* allocation flags - the lower 16 bits are used by core ion, the upper 16
* bits are reserved for use by the heaps themselves.
*/
#define ION_FLAG_CACHED (0x1 << 0) /* mappings of this buffer should be
cached, ion will do cache
maintenance when the buffer is
mapped for dma */
#define ION_FLAG_CACHED_NEEDS_SYNC (0x1 << 1) /* mappings of this buffer
will created at mmap time,
if this is set caches
must be managed manually */
#define ION_FLAG_NOT_ZERO_BUFFER (0x1 << 2) /* do not zero buffer*/
/*
* mappings of this buffer should be cached, ion will do cache maintenance
* when the buffer is mapped for dma
*/
#define ION_FLAG_CACHED 1
#define ION_FLAG_SECURE_BUFFER (0x1 << 3)
/*
* mappings of this buffer will created at mmap time, if this is set
* caches must be managed manually
*/
#define ION_FLAG_CACHED_NEEDS_SYNC 2
#define ION_FLAG_GRAPHIC_BUFFER (0x1 << 4)
#define ION_FLAG_GRAPHIC_GPU_BUFFER (0x1 << 5)
/**
* DOC: Ion Userspace API
@@ -128,36 +144,6 @@ struct ion_custom_data {
unsigned long arg;
};
#define MAX_HEAP_NAME 32
/**
* struct ion_heap_data - data about a heap
* @name - first 32 characters of the heap name
* @type - heap type
* @heap_id - heap id for the heap
*/
struct ion_heap_data {
char name[MAX_HEAP_NAME];
__u32 type;
__u32 heap_id;
__u32 reserved0;
__u32 reserved1;
__u32 reserved2;
};
/**
* struct ion_heap_query - collection of data about all heaps
* @cnt - total number of heaps to be copied
* @heaps - buffer to copy heap data
*/
struct ion_heap_query {
__u32 cnt; /* Total number of heaps to be copied */
__u32 reserved0; /* align to 64bits */
__u64 heaps; /* buffer to be populated */
__u32 reserved1;
__u32 reserved2;
};
#define ION_IOC_MAGIC 'I'
/**
@@ -225,12 +211,33 @@ struct ion_heap_query {
#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
/**
* DOC: ION_IOC_HEAP_QUERY - information about available heaps
* struct ion_map_iommu_data - metadata passed between userspace for iommu mapping
* @handle: the handle of buffer
* @format: the format of iommu mapping
*
* Takes an ion_heap_query structure and populates information about
* available Ion heaps.
* Provided by userspace as an argument to the ioctl
*/
#define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, \
struct ion_heap_query)
struct iommu_map_format;
struct ion_map_iommu_data {
ion_user_handle_t handle;
struct iommu_map_format format;
};
/**
* DOC: ION_IOC_MAP_IOMMU - map a buffr to iova
*/
#define ION_IOC_MAP_IOMMU _IOWR(ION_IOC_MAGIC, \
8, struct ion_map_iommu_data)
/**
* DOC: ION_IOC_UNMAP_IOMMU - destory iommu mapping of a buffer
*/
#define ION_IOC_UNMAP_IOMMU _IOWR(ION_IOC_MAGIC, \
9, struct ion_map_iommu_data)
/**
* DOC: ION_IOC_INV - invalidate a shared file descriptors in cache
*/
#define ION_IOC_INV _IOWR(ION_IOC_MAGIC, 10, struct ion_fd_data)
#endif /* _UAPI_LINUX_ION_H */
+2 -2
View File
@@ -59,12 +59,12 @@ static inline phys_addr_t hisi_iommu_domain_iova_to_phys(unsigned long iova)
{
return 0;
}
unsigned int hisi_iommu_page_size (void)
static inline unsigned int hisi_iommu_page_size (void)
{
return SZ_4K;
}
bool hisi_iommu_off_on(void)
static inline bool hisi_iommu_off_on(void)
{
return false;
}
-2
View File
@@ -123,7 +123,6 @@ enum iommu_attr {
DOMAIN_ATTR_MAX,
};
#ifdef CONFIG_HISI_IOMMU
/* metadata for iommu mapping */
struct iommu_map_format {
unsigned long iova_start;
@@ -143,7 +142,6 @@ struct tile_format {
unsigned long phys_page_line;
unsigned long virt_page_line;
};
#endif
/**
* struct iommu_dm_region - descriptor for a direct mapped memory region