diff options
Diffstat (limited to 'drivers/gpu/ion/msm/msm_ion.c')
| -rw-r--r-- | drivers/gpu/ion/msm/msm_ion.c | 1061 |
1 files changed, 0 insertions, 1061 deletions
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c deleted file mode 100644 index 5fa2514628a..00000000000 --- a/drivers/gpu/ion/msm/msm_ion.c +++ /dev/null @@ -1,1061 +0,0 @@ -/* Copyright (c) 2011-2013, The Linux Foundation. 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. - * - */ - -#include <linux/export.h> -#include <linux/err.h> -#include <linux/msm_ion.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/mm.h> -#include <linux/mm_types.h> -#include <linux/sched.h> -#include <linux/rwsem.h> -#include <linux/uaccess.h> -#include <linux/memblock.h> -#include <linux/dma-mapping.h> -#include <linux/dma-contiguous.h> -#include <mach/msm_memtypes.h> -#include <asm/cacheflush.h> -#include "../ion_priv.h" -#include "ion_cp_common.h" - -#define ION_COMPAT_STR "qcom,msm-ion" -#define ION_COMPAT_MEM_RESERVE_STR "qcom,msm-ion-reserve" - -static struct ion_device *idev; -static int num_heaps; -static struct ion_heap **heaps; - -struct ion_heap_desc { - unsigned int id; - enum ion_heap_type type; - const char *name; - unsigned int permission_type; -}; - - -#ifdef CONFIG_OF -static struct ion_heap_desc ion_heap_meta[] = { - { - .id = ION_SYSTEM_HEAP_ID, - .name = ION_SYSTEM_HEAP_NAME, - }, - { - .id = ION_SYSTEM_CONTIG_HEAP_ID, - .name = ION_KMALLOC_HEAP_NAME, - }, - { - .id = ION_CP_MM_HEAP_ID, - .name = ION_MM_HEAP_NAME, - .permission_type = IPT_TYPE_MM_CARVEOUT, - }, - { - .id = ION_MM_FIRMWARE_HEAP_ID, - .name = ION_MM_FIRMWARE_HEAP_NAME, - }, - { - .id = ION_CP_MFC_HEAP_ID, - .name = ION_MFC_HEAP_NAME, - .permission_type = IPT_TYPE_MFC_SHAREDMEM, - }, - { - .id = ION_SF_HEAP_ID, - .name = ION_SF_HEAP_NAME, - }, - { - .id = ION_QSECOM_HEAP_ID, - .name = ION_QSECOM_HEAP_NAME, - }, - { - .id = ION_AUDIO_HEAP_ID, - .name = ION_AUDIO_HEAP_NAME, - }, - { - .id = ION_PIL1_HEAP_ID, - .name = ION_PIL1_HEAP_NAME, - }, - { - .id = ION_PIL2_HEAP_ID, - .name = ION_PIL2_HEAP_NAME, - }, - { - .id = ION_CP_WB_HEAP_ID, - .name = ION_WB_HEAP_NAME, - }, - { - .id = ION_CAMERA_HEAP_ID, - .name = ION_CAMERA_HEAP_NAME, - }, - { - .id = ION_ADSP_HEAP_ID, - .name = ION_ADSP_HEAP_NAME, - } -}; -#endif - -struct ion_client *msm_ion_client_create(unsigned int heap_mask, - const char *name) -{ - /* - * The assumption is that if there is a NULL device, the ion - * driver has not yet probed. - */ - if (idev == NULL) - return ERR_PTR(-EPROBE_DEFER); - - if (IS_ERR(idev)) - return (struct ion_client *)idev; - - return ion_client_create(idev, name); -} -EXPORT_SYMBOL(msm_ion_client_create); - -int msm_ion_secure_heap(int heap_id) -{ - return ion_secure_heap(idev, heap_id, ION_CP_V1, NULL); -} -EXPORT_SYMBOL(msm_ion_secure_heap); - -int msm_ion_unsecure_heap(int heap_id) -{ - return ion_unsecure_heap(idev, heap_id, ION_CP_V1, NULL); -} -EXPORT_SYMBOL(msm_ion_unsecure_heap); - -int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage) -{ - return ion_secure_heap(idev, heap_id, ION_CP_V2, (void *)usage); -} -EXPORT_SYMBOL(msm_ion_secure_heap_2_0); - -int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage) -{ - return ion_unsecure_heap(idev, heap_id, ION_CP_V2, (void *)usage); -} -EXPORT_SYMBOL(msm_ion_unsecure_heap_2_0); - -int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, - void *vaddr, unsigned long len, unsigned int cmd) -{ - return ion_do_cache_op(client, handle, vaddr, 0, len, cmd); -} -EXPORT_SYMBOL(msm_ion_do_cache_op); - -static int ion_no_pages_cache_ops(struct ion_client *client, - struct ion_handle *handle, - void *vaddr, - unsigned int offset, unsigned int length, - unsigned int cmd) -{ - void (*outer_cache_op)(phys_addr_t, phys_addr_t) = NULL; - unsigned int size_to_vmap, total_size; - int i, j, ret; - void *ptr = NULL; - ion_phys_addr_t buff_phys = 0; - ion_phys_addr_t buff_phys_start = 0; - size_t buf_length = 0; - - ret = ion_phys(client, handle, &buff_phys_start, &buf_length); - if (ret) - return -EINVAL; - - buff_phys = buff_phys_start; - - if (!vaddr) { - /* - * Split the vmalloc space into smaller regions in - * order to clean and/or invalidate the cache. - */ - size_to_vmap = ((VMALLOC_END - VMALLOC_START)/8); - total_size = buf_length; - - for (i = 0; i < total_size; i += size_to_vmap) { - size_to_vmap = min(size_to_vmap, total_size - i); - for (j = 0; j < 10 && size_to_vmap; ++j) { - ptr = ioremap(buff_phys, size_to_vmap); - if (ptr) { - switch (cmd) { - case ION_IOC_CLEAN_CACHES: - dmac_clean_range(ptr, - ptr + size_to_vmap); - outer_cache_op = - outer_clean_range; - break; - case ION_IOC_INV_CACHES: - dmac_inv_range(ptr, - ptr + size_to_vmap); - outer_cache_op = - outer_inv_range; - break; - case ION_IOC_CLEAN_INV_CACHES: - dmac_flush_range(ptr, - ptr + size_to_vmap); - outer_cache_op = - outer_flush_range; - break; - default: - return -EINVAL; - } - buff_phys += size_to_vmap; - break; - } else { - size_to_vmap >>= 1; - } - } - if (!ptr) { - pr_err("Couldn't io-remap the memory\n"); - return -EINVAL; - } - iounmap(ptr); - } - } else { - switch (cmd) { - case ION_IOC_CLEAN_CACHES: - dmac_clean_range(vaddr, vaddr + length); - outer_cache_op = outer_clean_range; - break; - case ION_IOC_INV_CACHES: - dmac_inv_range(vaddr, vaddr + length); - outer_cache_op = outer_inv_range; - break; - case ION_IOC_CLEAN_INV_CACHES: - dmac_flush_range(vaddr, vaddr + length); - outer_cache_op = outer_flush_range; - break; - default: - return -EINVAL; - } - } - - if (!outer_cache_op) - return -EINVAL; - - outer_cache_op(buff_phys_start + offset, - buff_phys_start + offset + length); - - return 0; -} - -#ifdef CONFIG_OUTER_CACHE -static void ion_pages_outer_cache_op(void (*op)(phys_addr_t, phys_addr_t), - struct sg_table *table) -{ - unsigned long pstart; - struct scatterlist *sg; - int i; - for_each_sg(table->sgl, sg, table->nents, i) { - struct page *page = sg_page(sg); - pstart = page_to_phys(page); - /* - * If page -> phys is returning NULL, something - * has really gone wrong... - */ - if (!pstart) { - WARN(1, "Could not translate virtual address to physical address\n"); - return; - } - op(pstart, pstart + PAGE_SIZE); - } -} -#else -static void ion_pages_outer_cache_op(void (*op)(phys_addr_t, phys_addr_t), - struct sg_table *table) -{ - -} -#endif - -static int ion_pages_cache_ops(struct ion_client *client, - struct ion_handle *handle, - void *vaddr, unsigned int offset, unsigned int length, - unsigned int cmd) -{ - void (*outer_cache_op)(phys_addr_t, phys_addr_t); - struct sg_table *table = NULL; - - table = ion_sg_table(client, handle); - if (IS_ERR_OR_NULL(table)) - return PTR_ERR(table); - - switch (cmd) { - case ION_IOC_CLEAN_CACHES: - if (!vaddr) - dma_sync_sg_for_device(NULL, table->sgl, - table->nents, DMA_TO_DEVICE); - else - dmac_clean_range(vaddr, vaddr + length); - outer_cache_op = outer_clean_range; - break; - case ION_IOC_INV_CACHES: - if (!vaddr) - dma_sync_sg_for_cpu(NULL, table->sgl, - table->nents, DMA_FROM_DEVICE); - else - dmac_inv_range(vaddr, vaddr + length); - outer_cache_op = outer_inv_range; - break; - case ION_IOC_CLEAN_INV_CACHES: - if (!vaddr) { - dma_sync_sg_for_device(NULL, table->sgl, - table->nents, DMA_TO_DEVICE); - dma_sync_sg_for_cpu(NULL, table->sgl, - table->nents, DMA_FROM_DEVICE); - } else { - dmac_flush_range(vaddr, vaddr + length); - } - outer_cache_op = outer_flush_range; - break; - default: - return -EINVAL; - } - - ion_pages_outer_cache_op(outer_cache_op, table); - - return 0; -} - -int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, - void *uaddr, unsigned long offset, unsigned long len, - unsigned int cmd) -{ - int ret = -EINVAL; - unsigned long flags; - struct sg_table *table; - struct page *page; - - ret = ion_handle_get_flags(client, handle, &flags); - if (ret) - return -EINVAL; - - if (!ION_IS_CACHED(flags)) - return 0; - - if (flags & ION_FLAG_SECURE) - return 0; - - table = ion_sg_table(client, handle); - - if (IS_ERR_OR_NULL(table)) - return PTR_ERR(table); - - page = sg_page(table->sgl); - - if (page) - ret = ion_pages_cache_ops(client, handle, uaddr, - offset, len, cmd); - else - ret = ion_no_pages_cache_ops(client, handle, uaddr, - offset, len, cmd); - - return ret; - -} - -static void msm_ion_allocate(struct ion_platform_heap *heap) -{ - - if (!heap->base && heap->extra_data) { - WARN(1, "Specifying carveout heaps without a base is deprecated. Convert to the DMA heap type instead"); - return; - } -} - -static int is_heap_overlapping(const struct ion_platform_heap *heap1, - const struct ion_platform_heap *heap2) -{ - ion_phys_addr_t heap1_base = heap1->base; - ion_phys_addr_t heap2_base = heap2->base; - ion_phys_addr_t heap1_end = heap1->base + heap1->size - 1; - ion_phys_addr_t heap2_end = heap2->base + heap2->size - 1; - - if (heap1_base == heap2_base) - return 1; - if (heap1_base < heap2_base && heap1_end >= heap2_base) - return 1; - if (heap2_base < heap1_base && heap2_end >= heap1_base) - return 1; - return 0; -} - -static void check_for_heap_overlap(const struct ion_platform_heap heap_list[], - unsigned long nheaps) -{ - unsigned long i; - unsigned long j; - - for (i = 0; i < nheaps; ++i) { - const struct ion_platform_heap *heap1 = &heap_list[i]; - if (!heap1->base) - continue; - for (j = i + 1; j < nheaps; ++j) { - const struct ion_platform_heap *heap2 = &heap_list[j]; - if (!heap2->base) - continue; - if (is_heap_overlapping(heap1, heap2)) { - panic("Memory in heap %s overlaps with heap %s\n", - heap1->name, heap2->name); - } - } - } -} - -#ifdef CONFIG_OF -static int msm_init_extra_data(struct device_node *node, - struct ion_platform_heap *heap, - const struct ion_heap_desc *heap_desc) -{ - int ret = 0; - - switch ((int) heap->type) { - case ION_HEAP_TYPE_CP: - { - heap->extra_data = kzalloc(sizeof(struct ion_cp_heap_pdata), - GFP_KERNEL); - if (!heap->extra_data) { - ret = -ENOMEM; - } else { - struct ion_cp_heap_pdata *extra = heap->extra_data; - extra->permission_type = heap_desc->permission_type; - } - break; - } - case ION_HEAP_TYPE_CARVEOUT: - { - heap->extra_data = kzalloc(sizeof(struct ion_co_heap_pdata), - GFP_KERNEL); - if (!heap->extra_data) - ret = -ENOMEM; - break; - } - case ION_HEAP_TYPE_SECURE_DMA: - { - unsigned int val; - - ret = of_property_read_u32(node, - "qcom,default-prefetch-size", &val); - - if (!ret) { - heap->extra_data = kzalloc(sizeof(struct ion_cma_pdata), - GFP_KERNEL); - - if (!heap->extra_data) { - ret = -ENOMEM; - } else { - struct ion_cma_pdata *extra = heap->extra_data; - extra->default_prefetch_size = val; - } - } else { - ret = 0; - } - break; - } - default: - heap->extra_data = 0; - break; - } - return ret; -} - -#define MAKE_HEAP_TYPE_MAPPING(h) { .name = #h, \ - .heap_type = ION_HEAP_TYPE_##h, } - -static struct heap_types_info { - const char *name; - int heap_type; -} heap_types_info[] = { - MAKE_HEAP_TYPE_MAPPING(SYSTEM), - MAKE_HEAP_TYPE_MAPPING(SYSTEM_CONTIG), - MAKE_HEAP_TYPE_MAPPING(CARVEOUT), - MAKE_HEAP_TYPE_MAPPING(CHUNK), - MAKE_HEAP_TYPE_MAPPING(DMA), - MAKE_HEAP_TYPE_MAPPING(CP), - MAKE_HEAP_TYPE_MAPPING(SECURE_DMA), - MAKE_HEAP_TYPE_MAPPING(REMOVED), -}; - -static int msm_ion_get_heap_type_from_dt_node(struct device_node *node, - int *heap_type) -{ - const char *name; - int i, ret = -EINVAL; - ret = of_property_read_string(node, "qcom,ion-heap-type", &name); - if (ret) - goto out; - for (i = 0; i < ARRAY_SIZE(heap_types_info); ++i) { - if (!strcmp(heap_types_info[i].name, name)) { - *heap_type = heap_types_info[i].heap_type; - ret = 0; - goto out; - } - } - WARN(1, "Unknown heap type: %s. You might need to update heap_types_info in %s", - name, __FILE__); -out: - return ret; -} - -static int msm_ion_populate_heap(struct device_node *node, - struct ion_platform_heap *heap) -{ - unsigned int i; - int ret = -EINVAL, heap_type = -1; - unsigned int len = ARRAY_SIZE(ion_heap_meta); - for (i = 0; i < len; ++i) { - if (ion_heap_meta[i].id == heap->id) { - heap->name = ion_heap_meta[i].name; - ret = msm_ion_get_heap_type_from_dt_node(node, - &heap_type); - if (ret) - break; - heap->type = heap_type; - ret = msm_init_extra_data(node, heap, - &ion_heap_meta[i]); - break; - } - } - if (ret) - pr_err("%s: Unable to populate heap, error: %d", __func__, ret); - return ret; -} - -static void free_pdata(const struct ion_platform_data *pdata) -{ - unsigned int i; - for (i = 0; i < pdata->nr; ++i) - kfree(pdata->heaps[i].extra_data); - kfree(pdata->heaps); - kfree(pdata); -} - -static void msm_ion_get_heap_align(struct device_node *node, - struct ion_platform_heap *heap) -{ - unsigned int val; - - int ret = of_property_read_u32(node, "qcom,heap-align", &val); - if (!ret) { - switch ((int) heap->type) { - case ION_HEAP_TYPE_CP: - { - struct ion_cp_heap_pdata *extra = - heap->extra_data; - extra->align = val; - break; - } - case ION_HEAP_TYPE_CARVEOUT: - { - struct ion_co_heap_pdata *extra = - heap->extra_data; - extra->align = val; - break; - } - default: - pr_err("ION-heap %s: Cannot specify alignment for this type of heap\n", - heap->name); - break; - } - } -} - -static int msm_ion_get_heap_size(struct device_node *node, - struct ion_platform_heap *heap) -{ - unsigned int val; - int ret = 0; - u32 out_values[2]; - struct device_node *pnode; - - ret = of_property_read_u32(node, "qcom,memory-reservation-size", &val); - if (!ret) - heap->size = val; - - ret = of_property_read_u32_array(node, "qcom,memory-fixed", - out_values, 2); - if (!ret) { - heap->size = out_values[1]; - goto out; - } - - pnode = of_parse_phandle(node, "linux,contiguous-region", 0); - if (pnode != NULL) { - const u32 *addr; - u64 size; - - addr = of_get_address(pnode, 0, &size, NULL); - if (!addr) { - of_node_put(pnode); - ret = -EINVAL; - goto out; - } - heap->size = (u32) size; - ret = 0; - of_node_put(pnode); - } - - ret = 0; -out: - return ret; -} - -static void msm_ion_get_heap_base(struct device_node *node, - struct ion_platform_heap *heap) -{ - u32 out_values[2]; - int ret = 0; - struct device_node *pnode; - - ret = of_property_read_u32_array(node, "qcom,memory-fixed", - out_values, 2); - if (!ret) - heap->base = out_values[0]; - - pnode = of_parse_phandle(node, "linux,contiguous-region", 0); - if (pnode != NULL) { - heap->base = cma_get_base(heap->priv); - of_node_put(pnode); - } - - return; -} - -static void msm_ion_get_heap_adjacent(struct device_node *node, - struct ion_platform_heap *heap) -{ - unsigned int val; - int ret = of_property_read_u32(node, "qcom,heap-adjacent", &val); - if (!ret) { - switch (heap->type) { - case ION_HEAP_TYPE_CARVEOUT: - { - struct ion_co_heap_pdata *extra = heap->extra_data; - extra->adjacent_mem_id = val; - break; - } - default: - pr_err("ION-heap %s: Cannot specify adjcent mem id for this type of heap\n", - heap->name); - break; - } - } else { - switch (heap->type) { - case ION_HEAP_TYPE_CARVEOUT: - { - struct ion_co_heap_pdata *extra = heap->extra_data; - extra->adjacent_mem_id = INVALID_HEAP_ID; - break; - } - default: - break; - } - } -} - -static struct ion_platform_data *msm_ion_parse_dt(struct platform_device *pdev) -{ - struct ion_platform_data *pdata = 0; - struct ion_platform_heap *heaps = NULL; - struct device_node *node; - struct platform_device *new_dev = NULL; - const struct device_node *dt_node = pdev->dev.of_node; - uint32_t val = 0; - int ret = 0; - uint32_t num_heaps = 0; - int idx = 0; - - for_each_child_of_node(dt_node, node) - num_heaps++; - - if (!num_heaps) - return ERR_PTR(-EINVAL); - - pdata = kzalloc(sizeof(struct ion_platform_data), GFP_KERNEL); - if (!pdata) - return ERR_PTR(-ENOMEM); - - heaps = kzalloc(sizeof(struct ion_platform_heap)*num_heaps, GFP_KERNEL); - if (!heaps) { - kfree(pdata); - return ERR_PTR(-ENOMEM); - } - - pdata->heaps = heaps; - pdata->nr = num_heaps; - - for_each_child_of_node(dt_node, node) { - new_dev = of_platform_device_create(node, NULL, &pdev->dev); - if (!new_dev) { - pr_err("Failed to create device %s\n", node->name); - goto free_heaps; - } - - pdata->heaps[idx].priv = &new_dev->dev; - /** - * TODO: Replace this with of_get_address() when this patch - * gets merged: http:// - * permalink.gmane.org/gmane.linux.drivers.devicetree/18614 - */ - ret = of_property_read_u32(node, "reg", &val); - if (ret) { - pr_err("%s: Unable to find reg key", __func__); - goto free_heaps; - } - pdata->heaps[idx].id = val; - - ret = msm_ion_populate_heap(node, &pdata->heaps[idx]); - if (ret) - goto free_heaps; - - msm_ion_get_heap_base(node, &pdata->heaps[idx]); - msm_ion_get_heap_align(node, &pdata->heaps[idx]); - - ret = msm_ion_get_heap_size(node, &pdata->heaps[idx]); - if (ret) - goto free_heaps; - - msm_ion_get_heap_adjacent(node, &pdata->heaps[idx]); - - ++idx; - } - return pdata; - -free_heaps: - free_pdata(pdata); - return ERR_PTR(ret); -} -#else -static struct ion_platform_data *msm_ion_parse_dt(struct platform_device *pdev) -{ - return NULL; -} - -static void free_pdata(const struct ion_platform_data *pdata) -{ - -} -#endif - -static int check_vaddr_bounds(unsigned long start, unsigned long end) -{ - struct mm_struct *mm = current->active_mm; - struct vm_area_struct *vma; - int ret = 1; - - if (end < start) - goto out; - - vma = find_vma(mm, start); - if (vma && vma->vm_start < end) { - if (start < vma->vm_start) - goto out; - if (end > vma->vm_end) - goto out; - ret = 0; - } - -out: - return ret; -} - -int ion_heap_allow_secure_allocation(enum ion_heap_type type) -{ - return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP) || - type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA); -} - -int ion_heap_allow_handle_secure(enum ion_heap_type type) -{ - return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP) || - type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA); -} - -int ion_heap_allow_heap_secure(enum ion_heap_type type) -{ - return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP); -} - -static long msm_ion_custom_ioctl(struct ion_client *client, - unsigned int cmd, - unsigned long arg) -{ - switch (cmd) { - case ION_IOC_CLEAN_CACHES: - case ION_IOC_INV_CACHES: - case ION_IOC_CLEAN_INV_CACHES: - { - struct ion_flush_data data; - unsigned long start, end; - struct ion_handle *handle = NULL; - int ret; - struct mm_struct *mm = current->active_mm; - - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_flush_data))) - return -EFAULT; - - if (data.handle > 0) { - handle = ion_handle_get_by_id(client, (int)data.handle); - if (IS_ERR(handle)) { - pr_info("%s: Could not find handle: %d\n", - __func__, (int)data.handle); - return PTR_ERR(handle); - } - } else { - handle = ion_import_dma_buf(client, data.fd); - if (IS_ERR(handle)) { - pr_info("%s: Could not import handle: %p\n", - __func__, handle); - return -EINVAL; - } - } - - down_read(&mm->mmap_sem); - - start = (unsigned long) data.vaddr; - end = (unsigned long) data.vaddr + data.length; - - if (start && check_vaddr_bounds(start, end)) { - pr_err("%s: virtual address %p is out of bounds\n", - __func__, data.vaddr); - ret = -EINVAL; - } else { - ret = ion_do_cache_op(client, handle, data.vaddr, - data.offset, data.length, cmd); - } - up_read(&mm->mmap_sem); - - ion_free(client, handle); - - if (ret < 0) - return ret; - break; - } - case ION_IOC_PREFETCH: - { - struct ion_prefetch_data data; - - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_prefetch_data))) - return -EFAULT; - - ion_walk_heaps(client, data.heap_id, (void *)data.len, - ion_secure_cma_prefetch); - break; - } - case ION_IOC_DRAIN: - { - struct ion_prefetch_data data; - - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_prefetch_data))) - return -EFAULT; - - ion_walk_heaps(client, data.heap_id, (void *)data.len, - ion_secure_cma_drain_pool); - break; - } - - default: - return -ENOTTY; - } - return 0; -} - -static struct ion_heap *msm_ion_heap_create(struct ion_platform_heap *heap_data) -{ - struct ion_heap *heap = NULL; - - switch ((int)heap_data->type) { - case ION_HEAP_TYPE_CP: - heap = ion_cp_heap_create(heap_data); - break; -#ifdef CONFIG_CMA - case ION_HEAP_TYPE_DMA: - heap = ion_cma_heap_create(heap_data); - break; - - case ION_HEAP_TYPE_SECURE_DMA: - heap = ion_secure_cma_heap_create(heap_data); - break; -#endif - case ION_HEAP_TYPE_REMOVED: - heap = ion_removed_heap_create(heap_data); - break; - - default: - heap = ion_heap_create(heap_data); - } - - if (IS_ERR_OR_NULL(heap)) { - pr_err("%s: error creating heap %s type %d base %pa size %zu\n", - __func__, heap_data->name, heap_data->type, - &heap_data->base, heap_data->size); - return ERR_PTR(-EINVAL); - } - - heap->name = heap_data->name; - heap->id = heap_data->id; - heap->priv = heap_data->priv; - return heap; -} - -static void msm_ion_heap_destroy(struct ion_heap *heap) -{ - if (!heap) - return; - - switch ((int)heap->type) { - case ION_HEAP_TYPE_CP: - ion_cp_heap_destroy(heap); - break; -#ifdef CONFIG_CMA - case ION_HEAP_TYPE_DMA: - ion_cma_heap_destroy(heap); - break; - case ION_HEAP_TYPE_SECURE_DMA: - ion_secure_cma_heap_destroy(heap); - break; -#endif - case ION_HEAP_TYPE_REMOVED: - ion_removed_heap_destroy(heap); - break; - default: - ion_heap_destroy(heap); - } -} - -static int msm_ion_probe(struct platform_device *pdev) -{ - static struct ion_device *new_dev; - struct ion_platform_data *pdata; - unsigned int pdata_needs_to_be_freed; - int err = -1; - int i; - if (pdev->dev.of_node) { - pdata = msm_ion_parse_dt(pdev); - if (IS_ERR(pdata)) { - err = PTR_ERR(pdata); - goto out; - } - pdata_needs_to_be_freed = 1; - } else { - pdata = pdev->dev.platform_data; - pdata_needs_to_be_freed = 0; - } - - num_heaps = pdata->nr; - - heaps = kcalloc(pdata->nr, sizeof(struct ion_heap *), GFP_KERNEL); - - if (!heaps) { - err = -ENOMEM; - goto out; - } - - new_dev = ion_device_create(msm_ion_custom_ioctl); - if (IS_ERR_OR_NULL(new_dev)) { - /* - * set this to the ERR to indicate to the clients - * that Ion failed to probe. - */ - idev = new_dev; - err = PTR_ERR(new_dev); - goto freeheaps; - } - - /* create the heaps as specified in the board file */ - for (i = 0; i < num_heaps; i++) { - struct ion_platform_heap *heap_data = &pdata->heaps[i]; - msm_ion_allocate(heap_data); - - heap_data->has_outer_cache = pdata->has_outer_cache; - heaps[i] = msm_ion_heap_create(heap_data); - if (IS_ERR_OR_NULL(heaps[i])) { - heaps[i] = 0; - continue; - } else { - if (heap_data->size) - pr_info("ION heap %s created at %pa with size %zx\n", - heap_data->name, - &heap_data->base, - heap_data->size); - else - pr_info("ION heap %s created\n", - heap_data->name); - } - - ion_device_add_heap(new_dev, heaps[i]); - } - check_for_heap_overlap(pdata->heaps, num_heaps); - if (pdata_needs_to_be_freed) - free_pdata(pdata); - - platform_set_drvdata(pdev, new_dev); - /* - * intentionally set this at the very end to allow probes to be deferred - * completely until Ion is setup - */ - idev = new_dev; - return 0; - -freeheaps: - kfree(heaps); - if (pdata_needs_to_be_freed) - free_pdata(pdata); -out: - return err; -} - -static int msm_ion_remove(struct platform_device *pdev) -{ - struct ion_device *idev = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < num_heaps; i++) - msm_ion_heap_destroy(heaps[i]); - - ion_device_destroy(idev); - kfree(heaps); - return 0; -} - -static struct of_device_id msm_ion_match_table[] = { - {.compatible = ION_COMPAT_STR}, - {}, -}; -EXPORT_COMPAT(ION_COMPAT_MEM_RESERVE_STR); - -static struct platform_driver msm_ion_driver = { - .probe = msm_ion_probe, - .remove = msm_ion_remove, - .driver = { - .name = "ion-msm", - .of_match_table = msm_ion_match_table, - }, -}; - -static int __init msm_ion_init(void) -{ - return platform_driver_register(&msm_ion_driver); -} - -static void __exit msm_ion_exit(void) -{ - platform_driver_unregister(&msm_ion_driver); -} - -subsys_initcall(msm_ion_init); -module_exit(msm_ion_exit); - |
