diff options
author | Arve Hjønnevåg <arve@android.com> | 2010-09-27 17:50:00 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2010-10-05 21:19:14 -0700 |
commit | 65ccc17e7cbac2773e5e8d7e289b2bdf386051c5 (patch) | |
tree | 45267182af79fb976a1eb9a8ebe299a246723ac2 /arch/arm/common/fiq_glue_setup.c | |
parent | 776dd2c87482de547f1ebf06e2d496ade39d1e1a (diff) |
ARM: Add fiq_glue
Change-Id: I27d2554e07d9de204e0a06696d38db51608d9f6b
Signed-off-by: Arve Hjønnevåg <arve@android.com>
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/common/fiq_glue_setup.c')
-rw-r--r-- | arch/arm/common/fiq_glue_setup.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/arch/arm/common/fiq_glue_setup.c b/arch/arm/common/fiq_glue_setup.c new file mode 100644 index 000000000000..f878ea079b4d --- /dev/null +++ b/arch/arm/common/fiq_glue_setup.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2010 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/percpu.h> +#include <linux/slab.h> +#include <asm/fiq.h> +#include <asm/fiq_glue.h> + +extern unsigned char fiq_glue, fiq_glue_end; +extern void fiq_glue_setup(void *func, void *data, void *sp); + +static struct fiq_handler fiq_debbuger_fiq_handler = { + .name = "fiq_glue", +}; +static __percpu void *fiq_stack; +static struct fiq_glue_handler *current_handler; +static DEFINE_MUTEX(fiq_glue_lock); + +static void fiq_glue_setup_helper(void *info) +{ + struct fiq_glue_handler *handler = info; + fiq_glue_setup(handler->fiq, handler, + __this_cpu_ptr(fiq_stack) + THREAD_START_SP); +} + +int fiq_glue_register_handler(struct fiq_glue_handler *handler) +{ + int ret; + + if (!handler || !handler->fiq) + return -EINVAL; + + mutex_lock(&fiq_glue_lock); + if (fiq_stack) { + ret = -EBUSY; + goto err_busy; + } + + fiq_stack = __alloc_percpu(THREAD_SIZE, L1_CACHE_BYTES); + if (WARN_ON(!fiq_stack)) { + ret = -ENOMEM; + goto err_alloc_fiq_stack; + } + + ret = claim_fiq(&fiq_debbuger_fiq_handler); + if (WARN_ON(ret)) + goto err_claim_fiq; + + current_handler = handler; + on_each_cpu(fiq_glue_setup_helper, handler, true); + set_fiq_handler(&fiq_glue, &fiq_glue_end - &fiq_glue); + +err_claim_fiq: + if (ret) { + free_percpu(fiq_stack); + fiq_stack = NULL; + } +err_alloc_fiq_stack: +err_busy: + mutex_unlock(&fiq_glue_lock); + return ret; +} + +/** + * fiq_glue_resume - Restore fiqs after suspend or low power idle states + * + * This must be called before calling local_fiq_enable after returning from a + * power state where the fiq mode registers were lost. If a driver provided + * a resume hook when it registered the handler it will be called. + */ + +void fiq_glue_resume(void) +{ + if (!current_handler) + return; + fiq_glue_setup(current_handler->fiq, current_handler, + __this_cpu_ptr(fiq_stack) + THREAD_START_SP); + if (current_handler->resume) + current_handler->resume(current_handler); +} + |