123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782 |
- /*
- * Copyright (C) 2013 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 <asm/compiler.h>
- #include <linux/delay.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_platform.h>
- #include <linux/platform_device.h>
- #ifdef CONFIG_MT_TRUSTY_DEBUGFS
- #include <linux/random.h>
- #endif
- #include <linux/slab.h>
- #include <linux/stat.h>
- #include <linux/string.h>
- #include <linux/trusty/smcall.h>
- #include <linux/trusty/sm_err.h>
- #include <linux/trusty/trusty.h>
- #if 0
- #ifdef CONFIG_MTK_ENABLE_GENIEZONE
- #ifdef CONFIG_MTK_RAM_CONSOLE
- #include "trusty-ramconsole.h"
- #endif
- #endif
- #endif
- struct trusty_state;
- struct trusty_work {
- struct trusty_state *ts;
- struct work_struct work;
- };
- struct trusty_state {
- struct mutex smc_lock;
- struct atomic_notifier_head notifier;
- struct completion cpu_idle_completion;
- char *version_str;
- u32 api_version;
- struct device *dev;
- struct workqueue_struct *nop_wq;
- struct trusty_work __percpu *nop_works;
- struct list_head nop_queue;
- spinlock_t nop_lock; /* protects nop_queue */
- };
- #ifdef CONFIG_ARM64
- #define SMC_ARG0 "x0"
- #define SMC_ARG1 "x1"
- #define SMC_ARG2 "x2"
- #define SMC_ARG3 "x3"
- #define SMC_ARCH_EXTENSION ""
- #define SMC_REGISTERS_TRASHED "x4","x5","x6","x7","x8","x9","x10","x11", \
- "x12","x13","x14","x15","x16","x17"
- #else
- #define SMC_ARG0 "r0"
- #define SMC_ARG1 "r1"
- #define SMC_ARG2 "r2"
- #define SMC_ARG3 "r3"
- #define SMC_ARCH_EXTENSION ".arch_extension sec\n"
- #define SMC_REGISTERS_TRASHED "ip"
- #endif
- static inline ulong smc(ulong r0, ulong r1, ulong r2, ulong r3)
- {
- register ulong _r0 asm(SMC_ARG0) = r0;
- register ulong _r1 asm(SMC_ARG1) = r1;
- register ulong _r2 asm(SMC_ARG2) = r2;
- register ulong _r3 asm(SMC_ARG3) = r3;
- asm volatile(
- __asmeq("%0", SMC_ARG0)
- __asmeq("%1", SMC_ARG1)
- __asmeq("%2", SMC_ARG2)
- __asmeq("%3", SMC_ARG3)
- __asmeq("%4", SMC_ARG0)
- __asmeq("%5", SMC_ARG1)
- __asmeq("%6", SMC_ARG2)
- __asmeq("%7", SMC_ARG3)
- SMC_ARCH_EXTENSION
- "smc #0" /* switch to secure world */
- : "=r" (_r0), "=r" (_r1), "=r" (_r2), "=r" (_r3)
- : "r" (_r0), "r" (_r1), "r" (_r2), "r" (_r3)
- : SMC_REGISTERS_TRASHED);
- return _r0;
- }
- #ifdef CONFIG_TRUSTY_WDT_FIQ_ARMV7_SUPPORT
- s32 trusty_fast_call32_nodev(u32 smcnr, u32 a0, u32 a1, u32 a2)
- {
- BUG_ON(!SMC_IS_FASTCALL(smcnr));
- BUG_ON(SMC_IS_SMC64(smcnr));
- return smc(smcnr, a0, a1, a2);
- }
- #endif
- s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
- {
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- BUG_ON(!s);
- BUG_ON(!SMC_IS_FASTCALL(smcnr));
- BUG_ON(SMC_IS_SMC64(smcnr));
- return smc(smcnr, a0, a1, a2);
- }
- EXPORT_SYMBOL(trusty_fast_call32);
- #ifdef CONFIG_64BIT
- s64 trusty_fast_call64(struct device *dev, u64 smcnr, u64 a0, u64 a1, u64 a2)
- {
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- BUG_ON(!s);
- BUG_ON(!SMC_IS_FASTCALL(smcnr));
- BUG_ON(!SMC_IS_SMC64(smcnr));
- return smc(smcnr, a0, a1, a2);
- }
- #endif
- static ulong trusty_std_call_inner(struct device *dev, ulong smcnr,
- ulong a0, ulong a1, ulong a2)
- {
- ulong ret;
- int retry = 5;
- dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx)\n",
- __func__, smcnr, a0, a1, a2);
- while (true) {
- ret = smc(smcnr, a0, a1, a2);
- while ((s32)ret == SM_ERR_FIQ_INTERRUPTED)
- ret = smc(SMC_SC_RESTART_FIQ, 0, 0, 0);
- if ((int)ret != SM_ERR_BUSY || !retry)
- break;
- dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy, retry\n",
- __func__, smcnr, a0, a1, a2);
- retry--;
- }
- return ret;
- }
- static ulong trusty_std_call_helper(struct device *dev, ulong smcnr,
- ulong a0, ulong a1, ulong a2)
- {
- ulong ret;
- int sleep_time = 1;
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- while (true) {
- local_irq_disable();
- atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_PREPARE,
- NULL);
- ret = trusty_std_call_inner(dev, smcnr, a0, a1, a2);
- atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_RETURNED,
- NULL);
- local_irq_enable();
- if ((int)ret != SM_ERR_BUSY)
- break;
- if (sleep_time == 256)
- dev_warn(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy\n",
- __func__, smcnr, a0, a1, a2);
- dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy, wait %d ms\n",
- __func__, smcnr, a0, a1, a2, sleep_time);
- msleep(sleep_time);
- if (sleep_time < 1000)
- sleep_time <<= 1;
- dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) retry\n",
- __func__, smcnr, a0, a1, a2);
- }
- if (sleep_time > 256)
- dev_warn(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) busy cleared\n",
- __func__, smcnr, a0, a1, a2);
- return ret;
- }
- static void trusty_std_call_cpu_idle(struct trusty_state *s)
- {
- int ret;
- unsigned long timeout = HZ * 10;
- #ifdef CONFIG_TRUSTY_INTERRUPT_FIQ_ONLY
- timeout = HZ / 5; /* 200 ms */
- #endif
- ret = wait_for_completion_timeout(&s->cpu_idle_completion, timeout);
- if (!ret) {
- pr_warn("%s: timed out waiting for cpu idle to clear, retry anyway\n",
- __func__);
- }
- }
- s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
- {
- int ret;
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- BUG_ON(SMC_IS_FASTCALL(smcnr));
- BUG_ON(SMC_IS_SMC64(smcnr));
- if (smcnr != SMC_SC_NOP) {
- mutex_lock(&s->smc_lock);
- reinit_completion(&s->cpu_idle_completion);
- }
- dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) started\n",
- __func__, smcnr, a0, a1, a2);
- ret = trusty_std_call_helper(dev, smcnr, a0, a1, a2);
- while (ret == SM_ERR_INTERRUPTED || ret == SM_ERR_CPU_IDLE) {
- dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) interrupted\n",
- __func__, smcnr, a0, a1, a2);
- if (ret == SM_ERR_CPU_IDLE)
- trusty_std_call_cpu_idle(s);
- ret = trusty_std_call_helper(dev, SMC_SC_RESTART_LAST, 0, 0, 0);
- }
- dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) returned 0x%x\n",
- __func__, smcnr, a0, a1, a2, ret);
- WARN_ONCE(ret == SM_ERR_PANIC, "trusty crashed");
- if (smcnr == SMC_SC_NOP)
- complete(&s->cpu_idle_completion);
- else
- mutex_unlock(&s->smc_lock);
- return ret;
- }
- EXPORT_SYMBOL(trusty_std_call32);
- int trusty_call_notifier_register(struct device *dev, struct notifier_block *n)
- {
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- return atomic_notifier_chain_register(&s->notifier, n);
- }
- EXPORT_SYMBOL(trusty_call_notifier_register);
- int trusty_call_notifier_unregister(struct device *dev,
- struct notifier_block *n)
- {
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- return atomic_notifier_chain_unregister(&s->notifier, n);
- }
- EXPORT_SYMBOL(trusty_call_notifier_unregister);
- static int trusty_remove_child(struct device *dev, void *data)
- {
- platform_device_unregister(to_platform_device(dev));
- return 0;
- }
- ssize_t trusty_version_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- return scnprintf(buf, PAGE_SIZE, "%s\n", s->version_str);
- }
- DEVICE_ATTR(trusty_version, S_IRUSR, trusty_version_show, NULL);
- #if 0
- #ifdef CONFIG_MTK_ENABLE_GENIEZONE
- #ifdef CONFIG_MTK_RAM_CONSOLE
- static void init_gz_ramconsole(struct device *dev)
- {
- u32 low, high;
- #ifdef SRAM_TEST
- low = 0x0011E000;
- high = 0x00000000;
- #else
- unsigned long *gz_irq_pa;
- gz_irq_pa = aee_rr_rec_gz_irq_pa();
- dev_info(dev, "ram console: get PA %p\n", gz_irq_pa);
- low = (u32)(((u64)gz_irq_pa << 32) >> 32);
- high = (u32)((u64)gz_irq_pa >> 32);
- #endif
- dev_info(dev, "ram console: send ram console PA from kernel to GZ\n");
- trusty_std_call32(dev, MT_SMC_SC_SET_RAMCONSOLE, low, high, 0);
- }
- #endif
- #endif
- #endif
- #ifdef CONFIG_MT_TRUSTY_DEBUGFS
- ssize_t trusty_add(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- s32 a, b, ret;
- get_random_bytes(&a, sizeof(s32));
- a &= 0xFF;
- get_random_bytes(&b, sizeof(s32));
- b &= 0xFF;
- ret = trusty_std_call32(dev, MT_SMC_SC_ADD, a, b, 0);
- return scnprintf(buf, PAGE_SIZE, "%d + %d = %d, %s\n", a, b, ret,
- (a + b) == ret ? "PASS" : "FAIL");
- }
- DEVICE_ATTR(trusty_add, S_IRUSR, trusty_add, NULL);
- ssize_t trusty_threads(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- /* Dump Trusty threads info to memlog */
- trusty_fast_call32(dev, MT_SMC_FC_THREADS, 0, 0, 0);
- /* Dump threads info from memlog to kmsg*/
- trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
- return 0;
- }
- DEVICE_ATTR(trusty_threads, S_IRUSR, trusty_threads, NULL);
- ssize_t trusty_threadstats(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- /* Dump Trusty threads info to memlog */
- trusty_fast_call32(dev, MT_SMC_FC_THREADSTATS, 0, 0, 0);
- /* Dump threads info from memlog to kmsg*/
- trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
- return 0;
- }
- DEVICE_ATTR(trusty_threadstats, S_IRUSR, trusty_threadstats, NULL);
- ssize_t trusty_threadload(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- /* Dump Trusty threads info to memlog */
- trusty_fast_call32(dev, MT_SMC_FC_THREADLOAD, 0, 0, 0);
- /* Dump threads info from memlog to kmsg*/
- trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
- return 0;
- }
- DEVICE_ATTR(trusty_threadload, S_IRUSR, trusty_threadload, NULL);
- ssize_t trusty_heap_dump(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- /* Dump Trusty threads info to memlog */
- trusty_fast_call32(dev, MT_SMC_FC_HEAP_DUMP, 0, 0, 0);
- /* Dump threads info from memlog to kmsg*/
- trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
- return 0;
- }
- DEVICE_ATTR(trusty_heap_dump, S_IRUSR, trusty_heap_dump, NULL);
- ssize_t trusty_apps(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- /* Dump Trusty threads info to memlog */
- trusty_fast_call32(dev, MT_SMC_FC_APPS, 0, 0, 0);
- /* Dump threads info from memlog to kmsg*/
- trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
- return 0;
- }
- DEVICE_ATTR(trusty_apps, S_IRUSR, trusty_apps, NULL);
- ssize_t trusty_vdev_reset(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- trusty_std_call32(dev, SMC_SC_VDEV_RESET, 0, 0, 0);
- return 0;
- }
- DEVICE_ATTR(trusty_vdev_reset, S_IRUSR, trusty_vdev_reset, NULL);
- static void trusty_create_debugfs(struct trusty_state *s, struct device *pdev)
- {
- int ret;
- ret = device_create_file(pdev, &dev_attr_trusty_add);
- if (ret)
- goto err_create_trusty_add;
- ret = device_create_file(pdev, &dev_attr_trusty_threads);
- if (ret)
- goto err_create_trusty_threads;
- ret = device_create_file(pdev, &dev_attr_trusty_threadstats);
- if (ret)
- goto err_create_trusty_threadstats;
- ret = device_create_file(pdev, &dev_attr_trusty_threadload);
- if (ret)
- goto err_create_trusty_threadload;
- ret = device_create_file(pdev, &dev_attr_trusty_heap_dump);
- if (ret)
- goto err_create_trusty_heap_dump;
- ret = device_create_file(pdev, &dev_attr_trusty_apps);
- if (ret)
- goto err_create_trusty_apps;
- ret = device_create_file(pdev, &dev_attr_trusty_vdev_reset);
- if (ret)
- goto err_create_trusty_vdev_reset;
- return;
- err_create_trusty_vdev_reset:
- device_remove_file(pdev, &dev_attr_trusty_vdev_reset);
- err_create_trusty_apps:
- device_remove_file(pdev, &dev_attr_trusty_apps);
- err_create_trusty_heap_dump:
- device_remove_file(pdev, &dev_attr_trusty_heap_dump);
- err_create_trusty_threadload:
- device_remove_file(pdev, &dev_attr_trusty_threadload);
- err_create_trusty_threadstats:
- device_remove_file(pdev, &dev_attr_trusty_threadstats);
- err_create_trusty_threads:
- device_remove_file(pdev, &dev_attr_trusty_threads);
- err_create_trusty_add:
- device_remove_file(pdev, &dev_attr_trusty_add);
- }
- #endif /* CONFIG_MT_TRUSTY_DEBUGFS */
- const char *trusty_version_str_get(struct device *dev)
- {
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- return s->version_str;
- }
- EXPORT_SYMBOL(trusty_version_str_get);
- static void trusty_init_version(struct trusty_state *s, struct device *dev)
- {
- int ret;
- int i;
- int version_str_len;
- ret = trusty_fast_call32(dev, SMC_FC_GET_VERSION_STR, -1, 0, 0);
- if (ret <= 0)
- goto err_get_size;
- version_str_len = ret;
- s->version_str = kmalloc(version_str_len + 1, GFP_KERNEL);
- for (i = 0; i < version_str_len; i++) {
- ret = trusty_fast_call32(dev, SMC_FC_GET_VERSION_STR, i, 0, 0);
- if (ret < 0)
- goto err_get_char;
- s->version_str[i] = ret;
- }
- s->version_str[i] = '\0';
- dev_info(dev, "trusty version: %s\n", s->version_str);
- ret = device_create_file(dev, &dev_attr_trusty_version);
- if (ret)
- goto err_create_file;
- return;
- err_create_file:
- err_get_char:
- kfree(s->version_str);
- s->version_str = NULL;
- err_get_size:
- dev_err(dev, "failed to get version: %d\n", ret);
- }
- u32 trusty_get_api_version(struct device *dev)
- {
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- return s->api_version;
- }
- EXPORT_SYMBOL(trusty_get_api_version);
- static int trusty_init_api_version(struct trusty_state *s, struct device *dev)
- {
- u32 api_version;
- api_version = trusty_fast_call32(dev, SMC_FC_API_VERSION,
- TRUSTY_API_VERSION_CURRENT, 0, 0);
- if (api_version == SM_ERR_UNDEFINED_SMC)
- api_version = 0;
- if (api_version > TRUSTY_API_VERSION_CURRENT) {
- dev_err(dev, "unsupported api version %u > %u\n",
- api_version, TRUSTY_API_VERSION_CURRENT);
- return -EINVAL;
- }
- dev_info(dev, "selected api version: %u (requested %u)\n",
- api_version, TRUSTY_API_VERSION_CURRENT);
- s->api_version = api_version;
- return 0;
- }
- static bool dequeue_nop(struct trusty_state *s, u32 *args)
- {
- unsigned long flags;
- struct trusty_nop *nop = NULL;
- spin_lock_irqsave(&s->nop_lock, flags);
- if (!list_empty(&s->nop_queue)) {
- nop = list_first_entry(&s->nop_queue,
- struct trusty_nop, node);
- list_del_init(&nop->node);
- args[0] = nop->args[0];
- args[1] = nop->args[1];
- args[2] = nop->args[2];
- } else {
- args[0] = 0;
- args[1] = 0;
- args[2] = 0;
- }
- spin_unlock_irqrestore(&s->nop_lock, flags);
- return nop;
- }
- static void locked_nop_work_func(struct work_struct *work)
- {
- int ret;
- struct trusty_work *tw = container_of(work, struct trusty_work, work);
- struct trusty_state *s = tw->ts;
- dev_dbg(s->dev, "%s\n", __func__);
- ret = trusty_std_call32(s->dev, SMC_SC_LOCKED_NOP, 0, 0, 0);
- if (ret != 0)
- dev_info(s->dev, "%s: SMC_SC_LOCKED_NOP failed %d",
- __func__, ret);
- dev_dbg(s->dev, "%s: done\n", __func__);
- }
- static void nop_work_func(struct work_struct *work)
- {
- int ret;
- bool next;
- u32 args[3];
- struct trusty_work *tw = container_of(work, struct trusty_work, work);
- struct trusty_state *s = tw->ts;
- dev_dbg(s->dev, "%s:\n", __func__);
- dequeue_nop(s, args);
- do {
- dev_dbg(s->dev, "%s: %x %x %x\n",
- __func__, args[0], args[1], args[2]);
- ret = trusty_std_call32(s->dev, SMC_SC_NOP,
- args[0], args[1], args[2]);
- next = dequeue_nop(s, args);
- if (ret == SM_ERR_NOP_INTERRUPTED)
- next = true;
- else if (ret != SM_ERR_NOP_DONE)
- dev_info(s->dev, "%s: SMC_SC_NOP failed %d",
- __func__, ret);
- } while (next);
- dev_dbg(s->dev, "%s: done\n", __func__);
- }
- void trusty_enqueue_nop(struct device *dev, struct trusty_nop *nop)
- {
- unsigned long flags;
- struct trusty_work *tw;
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- preempt_disable();
- tw = this_cpu_ptr(s->nop_works);
- if (nop) {
- WARN_ON(s->api_version < TRUSTY_API_VERSION_SMP_NOP);
- spin_lock_irqsave(&s->nop_lock, flags);
- if (list_empty(&nop->node))
- list_add_tail(&nop->node, &s->nop_queue);
- spin_unlock_irqrestore(&s->nop_lock, flags);
- }
- queue_work(s->nop_wq, &tw->work);
- preempt_enable();
- }
- EXPORT_SYMBOL(trusty_enqueue_nop);
- void trusty_dequeue_nop(struct device *dev, struct trusty_nop *nop)
- {
- unsigned long flags;
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- if (WARN_ON(!nop))
- return;
- spin_lock_irqsave(&s->nop_lock, flags);
- if (!list_empty(&nop->node))
- list_del_init(&nop->node);
- spin_unlock_irqrestore(&s->nop_lock, flags);
- }
- EXPORT_SYMBOL(trusty_dequeue_nop);
- static int trusty_probe(struct platform_device *pdev)
- {
- int ret;
- unsigned int cpu;
- work_func_t work_func;
- struct trusty_state *s;
- struct device_node *node = pdev->dev.of_node;
- if (!node) {
- dev_err(&pdev->dev, "of_node required\n");
- return -EINVAL;
- }
- s = kzalloc(sizeof(*s), GFP_KERNEL);
- if (!s) {
- ret = -ENOMEM;
- goto err_allocate_state;
- }
- s->dev = &pdev->dev;
- spin_lock_init(&s->nop_lock);
- INIT_LIST_HEAD(&s->nop_queue);
- mutex_init(&s->smc_lock);
- ATOMIC_INIT_NOTIFIER_HEAD(&s->notifier);
- init_completion(&s->cpu_idle_completion);
- platform_set_drvdata(pdev, s);
- trusty_init_version(s, &pdev->dev);
- ret = trusty_init_api_version(s, &pdev->dev);
- if (ret < 0)
- goto err_api_version;
- s->nop_wq = alloc_workqueue("trusty-nop-wq", WQ_CPU_INTENSIVE, 0);
- if (!s->nop_wq) {
- ret = -ENODEV;
- dev_info(&pdev->dev, "Failed create trusty-nop-wq\n");
- goto err_create_nop_wq;
- }
- s->nop_works = alloc_percpu(struct trusty_work);
- if (!s->nop_works) {
- ret = -ENOMEM;
- dev_info(&pdev->dev, "Failed to allocate works\n");
- goto err_alloc_works;
- }
- if (s->api_version < TRUSTY_API_VERSION_SMP)
- work_func = locked_nop_work_func;
- else
- work_func = nop_work_func;
- for_each_possible_cpu(cpu) {
- struct trusty_work *tw = per_cpu_ptr(s->nop_works, cpu);
- tw->ts = s;
- INIT_WORK(&tw->work, work_func);
- }
- ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to add children: %d\n", ret);
- goto err_add_children;
- }
- #ifdef CONFIG_MT_TRUSTY_DEBUGFS
- trusty_create_debugfs(s, &pdev->dev);
- #endif
- #if 0
- #ifdef CONFIG_MTK_ENABLE_GENIEZONE
- #ifdef CONFIG_MTK_RAM_CONSOLE
- init_gz_ramconsole(&pdev->dev);
- #endif
- #endif
- #endif
- return 0;
- err_add_children:
- for_each_possible_cpu(cpu) {
- struct trusty_work *tw = per_cpu_ptr(s->nop_works, cpu);
- flush_work(&tw->work);
- }
- free_percpu(s->nop_works);
- err_alloc_works:
- destroy_workqueue(s->nop_wq);
- err_create_nop_wq:
- err_api_version:
- if (s->version_str) {
- device_remove_file(&pdev->dev, &dev_attr_trusty_version);
- kfree(s->version_str);
- }
- device_for_each_child(&pdev->dev, NULL, trusty_remove_child);
- mutex_destroy(&s->smc_lock);
- kfree(s);
- err_allocate_state:
- return ret;
- }
- static int trusty_remove(struct platform_device *pdev)
- {
- unsigned int cpu;
- struct trusty_state *s = platform_get_drvdata(pdev);
- device_for_each_child(&pdev->dev, NULL, trusty_remove_child);
- for_each_possible_cpu(cpu) {
- struct trusty_work *tw = per_cpu_ptr(s->nop_works, cpu);
- flush_work(&tw->work);
- }
- free_percpu(s->nop_works);
- destroy_workqueue(s->nop_wq);
- mutex_destroy(&s->smc_lock);
- if (s->version_str) {
- device_remove_file(&pdev->dev, &dev_attr_trusty_version);
- kfree(s->version_str);
- }
- kfree(s);
- return 0;
- }
- static const struct of_device_id trusty_of_match[] = {
- { .compatible = "android,trusty-smc-v1", },
- {},
- };
- static struct platform_driver trusty_driver = {
- .probe = trusty_probe,
- .remove = trusty_remove,
- .driver = {
- .name = "trusty",
- .owner = THIS_MODULE,
- .of_match_table = trusty_of_match,
- },
- };
- static int __init trusty_driver_init(void)
- {
- return platform_driver_register(&trusty_driver);
- }
- static void __exit trusty_driver_exit(void)
- {
- platform_driver_unregister(&trusty_driver);
- }
- subsys_initcall(trusty_driver_init);
- module_exit(trusty_driver_exit);
|