Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752777AbbDFP7L (ORCPT ); Mon, 6 Apr 2015 11:59:11 -0400 Received: from forward8l.mail.yandex.net ([84.201.143.141]:35771 "EHLO forward8l.mail.yandex.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751100AbbDFP7I (ORCPT ); Mon, 6 Apr 2015 11:59:08 -0400 From: Andrew Andrianov To: Greg Kroah-Hartman , =?UTF-8?q?Arve=20Hj=EF=BF=BDnnev=EF=BF=BDg?= , Riley Andrews , Chen Gang , Fabian Frederick Cc: Andrew Andrianov , linux-kernel@vger.kernel.org Subject: [PATCH 1/2] staging: ion: Add ion-physmem driver Date: Mon, 6 Apr 2015 18:58:54 +0300 Message-Id: <1428335934-10026-1-git-send-email-andrew@ncrmnt.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1428335363-9854-1-git-send-email-andrew@ncrmnt.org> References: <1428335363-9854-1-git-send-email-andrew@ncrmnt.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8044 Lines: 288 Signed-off-by: Andrew Andrianov --- drivers/staging/android/ion/Kconfig | 7 + drivers/staging/android/ion/Makefile | 5 +- drivers/staging/android/ion/ion_physmem.c | 237 +++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 drivers/staging/android/ion/ion_physmem.c diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig index 3452346..c558cf8 100644 --- a/drivers/staging/android/ion/Kconfig +++ b/drivers/staging/android/ion/Kconfig @@ -33,3 +33,10 @@ config ION_TEGRA help Choose this option if you wish to use ion on an nVidia Tegra. +config ION_PHYSMEM + bool "Generic PhysMem ION driver" + depends on ION + help + Provides a generic ION driver that registers the + /dev/ion device with heaps from devicetree entries. + This heaps are made of chunks of physical memory diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index b56fd2b..ac9856d 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -5,6 +5,7 @@ ifdef CONFIG_COMPAT obj-$(CONFIG_ION) += compat_ion.o endif -obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o -obj-$(CONFIG_ION_TEGRA) += tegra/ +obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o +obj-$(CONFIG_ION_PHYSMEM) += ion_physmem.o +obj-$(CONFIG_ION_TEGRA) += tegra/ diff --git a/drivers/staging/android/ion/ion_physmem.c b/drivers/staging/android/ion/ion_physmem.c new file mode 100644 index 0000000..e922d74 --- /dev/null +++ b/drivers/staging/android/ion/ion_physmem.c @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2015 RC Module + * Andrew Andrianov + * + * 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. + * + * Generic devicetree physmem driver for ION Memory Manager + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ion.h" +#include "ion_priv.h" + +#define DRVNAME "ion-physmem" + +static struct ion_device *idev; + +static const struct of_device_id of_match_table[] = { + { .compatible = "ion,physmem", }, + { /* end of list */ } +}; +MODULE_DEVICE_TABLE(of, of_match_table); + +/* +#define PHYSMAP_ION_DEBUG y +*/ + +struct physmem_ion_dev { + struct ion_platform_heap data; + struct ion_heap *heap; + int need_free_coherent; + void *freepage_ptr; +}; + +static long ion_physmem_custom_ioctl(struct ion_client *client, + unsigned int cmd, + unsigned long arg) +{ +/* Just an ugly debugging hack. */ +#ifdef PHYSMAP_ION_DEBUG + if ((cmd == 0xff)) { + ion_phys_addr_t addr; + size_t len; + struct ion_handle *hndl; + + printk(KERN_INFO "=== ION PHYSMEM DEBUG PRINTOUT ===\n"); + printk(KERN_INFO "N.B. DO disable CONFIG_ION_PHYSMEM_DEBUG in production\n"); + printk(KERN_INFO "Shared fd is %d\n", (int) arg); + hndl = ion_import_dma_buf(client, arg); + if (!hndl) { + printk(KERN_INFO "Failed to import shared descriptor.\n"); + return 0; + } + ion_phys(client, hndl, &addr, &len); + printk(KERN_INFO "shared buffer: phys 0x%lx len %ul\n", + addr, len); + printk(KERN_INFO "=== ION PHYSMEM DEBUG PRINTOUT ===\n"); + } +#endif + return 0; +} + +static int ion_physmem_probe(struct platform_device *pdev) +{ + int ret; + u32 ion_heap_id, ion_heap_align, ion_heap_type; + ion_phys_addr_t addr; + size_t size = 0; + const char *ion_heap_name; + struct resource *res; + struct physmem_ion_dev *ipdev; + + /* + Looks like we can only have one ION device in our system. + Therefore we call ion_device_create on first probe and only + add heaps to it on subsequent probe calls. + FixMe: Do we need to hold a spinlock here once device probing + becomes async? + */ + + if (!idev) { + idev = ion_device_create(ion_physmem_custom_ioctl); + dev_info(&pdev->dev, "ion-physmem: ION PhysMem Driver. (c) RC Module 2015\n"); + if (!idev) + return -ENOMEM; + } + + ipdev = kzalloc(sizeof(struct physmem_ion_dev), GFP_KERNEL); + if (!ipdev) + return -ENOMEM; + + platform_set_drvdata(pdev, ipdev); + + ret = of_property_read_u32(pdev->dev.of_node, "ion-heap-id", + &ion_heap_id); + if (ret != 0) + goto errfreeipdev; + + ret = of_property_read_u32(pdev->dev.of_node, "ion-heap-type", + &ion_heap_type); + if (ret != 0) + goto errfreeipdev; + + ret = of_property_read_u32(pdev->dev.of_node, "ion-heap-align", + &ion_heap_align); + if (ret != 0) + goto errfreeipdev; + + ret = of_property_read_string(pdev->dev.of_node, "ion-heap-name", + &ion_heap_name); + if (ret != 0) + goto errfreeipdev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory"); + /* Not always needed, throw no error if missing */ + if (res) { + /* Fill in some defaults */ + addr = res->start; + size = resource_size(res); + } + + switch (ion_heap_type) { + case ION_HEAP_TYPE_DMA: + if (res) { + ret = dma_declare_coherent_memory(&pdev->dev, + res->start, + res->start, + resource_size(res), + DMA_MEMORY_MAP | + DMA_MEMORY_EXCLUSIVE); + if (ret == 0) { + ret = -ENODEV; + goto errfreeipdev; + } + } + /* + * If no memory region declared in dt we assume that + * the user is okay with plain dma_alloc_coherent. + */ + break; + case ION_HEAP_TYPE_CARVEOUT: + case ION_HEAP_TYPE_CHUNK: + { + if (size == 0) { + ret = -EIO; + goto errfreeipdev; + } + ipdev->freepage_ptr = alloc_pages_exact(size, GFP_KERNEL); + if (ipdev->freepage_ptr) { + addr = virt_to_phys(ipdev->freepage_ptr); + } else { + ret = -ENOMEM; + goto errfreeipdev; + } + break; + } + } + + ipdev->data.id = ion_heap_id; + ipdev->data.type = ion_heap_type; + ipdev->data.name = ion_heap_name; + ipdev->data.align = ion_heap_align; + ipdev->data.base = addr; + ipdev->data.size = size; + /* This one make dma_declare_coherent_memory actually work */ + ipdev->data.priv = &pdev->dev; + + + ipdev->heap = ion_heap_create(&ipdev->data); + if (!ipdev->heap) + goto errfreeipdev; + + if (!try_module_get(THIS_MODULE)) + goto errfreeheap; + + ion_device_add_heap(idev, ipdev->heap); + + dev_info(&pdev->dev, "ion-physmem: heap %s id %d type %d align 0x%x at phys 0x%lx len %lu KiB\n", + ion_heap_name, ion_heap_id, ion_heap_type, ion_heap_align, + (unsigned long int) addr, ((unsigned long int) size / 1024)); + + return 0; + +errfreeheap: + kfree(ipdev->heap); +errfreeipdev: + kfree(ipdev); + return -ENOMEM; +} + +static int ion_physmem_remove(struct platform_device *pdev) +{ + struct physmem_ion_dev *ipdev = platform_get_drvdata(pdev); + + ion_heap_destroy(ipdev->heap); + if (ipdev->need_free_coherent) + dma_release_declared_memory(&pdev->dev); + if (ipdev->freepage_ptr) + free_pages_exact(ipdev->freepage_ptr, ipdev->data.size); + kfree(ipdev->heap); + kfree(ipdev); + module_put(THIS_MODULE); + return 0; +} + +static void __exit ion_physmem_exit(void) +{ + if (idev) + ion_device_destroy(idev); +} +__exitcall(ion_physmem_exit); + +static struct platform_driver ion_physmem_driver = { + .probe = ion_physmem_probe, + .remove = ion_physmem_remove, + .driver = { + .owner = THIS_MODULE, + .name = "ion-physmem", + .of_match_table = of_match_ptr(of_match_table), + }, +}; +module_platform_driver(ion_physmem_driver); + +MODULE_DESCRIPTION("Generic physmem driver for ION"); +MODULE_AUTHOR("Andrew Andrianov "); +MODULE_LICENSE("GPL"); -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/