Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c0dda2c authored by Arve Hjønnevåg's avatar Arve Hjønnevåg Committed by Dmitry Shmidt
Browse files

ANDROID: ARM: fiq_glue: Add custom fiq return handler api.



Change-Id: I5ff2764e85151ca0a88576542fda07c2d33dd065
Signed-off-by: default avatarArve Hjønnevåg <arve@android.com>
parent dad5647a
Loading
Loading
Loading
Loading
+16 −9
Original line number Diff line number Diff line
@@ -22,13 +22,14 @@
		/* fiq stack: r0-r15,cpsr,spsr of interrupted mode */

ENTRY(fiq_glue)
		/* store pc, cpsr from previous mode */
		/* store pc, cpsr from previous mode, reserve space for spsr */
		mrs	r12, spsr
		sub	r11, lr, #4
		sub	lr, lr, #4
		subs	r10, #1
		bne	nested_fiq

		stmfd	sp!, {r11-r12, lr}
		str	r12, [sp, #-8]!
		str	lr, [sp, #-4]!

		/* store r8-r14 from previous mode */
		sub	sp, sp, #(7 * 4)
@@ -85,12 +86,15 @@ fiq_from_usr_mode_exit:
		msr	cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)

		ldmfd	sp!, {r0-r7}
		add	sp, sp, #(7 * 4)
		ldmfd	sp!, {r11-r12, lr}
		ldr	lr, [sp, #(4 * 7)]
		ldr	r12, [sp, #(4 * 8)]
		add	sp, sp, #(10 * 4)
exit_fiq:
		msr	spsr_cxsf, r12
		add	r10, #1
		movs	pc, r11
		cmp	r11, #0
		moveqs	pc, lr
		bx	r11 /* jump to custom fiq return function */

nested_fiq:
		orr	r12, r12, #(PSR_F_BIT)
@@ -98,14 +102,17 @@ nested_fiq:

fiq_glue_end:

ENTRY(fiq_glue_setup) /* func, data, sp */
		mrs		r3, cpsr
ENTRY(fiq_glue_setup) /* func, data, sp, smc call number */
		stmfd		sp!, {r4}
		mrs		r4, cpsr
		msr		cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
		movs		r8, r0
		mov		r9, r1
		mov		sp, r2
		mov		r11, r3
		moveq		r10, #0
		movne		r10, #1
		msr		cpsr_c, r3
		msr		cpsr_c, r4
		ldmfd		sp!, {r4}
		bx		lr
+50 −3
Original line number Diff line number Diff line
@@ -18,20 +18,23 @@
#include <asm/fiq_glue.h>

extern unsigned char fiq_glue, fiq_glue_end;
extern void fiq_glue_setup(void *func, void *data, void *sp);
extern void fiq_glue_setup(void *func, void *data, void *sp,
			   fiq_return_handler_t fiq_return_handler);

static struct fiq_handler fiq_debbuger_fiq_handler = {
	.name = "fiq_glue",
};
DEFINE_PER_CPU(void *, fiq_stack);
static struct fiq_glue_handler *current_handler;
static fiq_return_handler_t fiq_return_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,
		__get_cpu_var(fiq_stack) + THREAD_START_SP);
		__get_cpu_var(fiq_stack) + THREAD_START_SP,
		fiq_return_handler);
}

int fiq_glue_register_handler(struct fiq_glue_handler *handler)
@@ -80,6 +83,49 @@ int fiq_glue_register_handler(struct fiq_glue_handler *handler)
	return ret;
}

static void fiq_glue_update_return_handler(void (*fiq_return)(void))
{
	fiq_return_handler = fiq_return;
	if (current_handler)
		on_each_cpu(fiq_glue_setup_helper, current_handler, true);
}

int fiq_glue_set_return_handler(void (*fiq_return)(void))
{
	int ret;

	mutex_lock(&fiq_glue_lock);
	if (fiq_return_handler) {
		ret = -EBUSY;
		goto err_busy;
	}
	fiq_glue_update_return_handler(fiq_return);
	ret = 0;
err_busy:
	mutex_unlock(&fiq_glue_lock);

	return ret;
}
EXPORT_SYMBOL(fiq_glue_set_return_handler);

int fiq_glue_clear_return_handler(void (*fiq_return)(void))
{
	int ret;

	mutex_lock(&fiq_glue_lock);
	if (WARN_ON(fiq_return_handler != fiq_return)) {
		ret = -EINVAL;
		goto err_inval;
	}
	fiq_glue_update_return_handler(NULL);
	ret = 0;
err_inval:
	mutex_unlock(&fiq_glue_lock);

	return ret;
}
EXPORT_SYMBOL(fiq_glue_clear_return_handler);

/**
 * fiq_glue_resume - Restore fiqs after suspend or low power idle states
 *
@@ -93,7 +139,8 @@ void fiq_glue_resume(void)
	if (!current_handler)
		return;
	fiq_glue_setup(current_handler->fiq, current_handler,
		__get_cpu_var(fiq_stack) + THREAD_START_SP);
		__get_cpu_var(fiq_stack) + THREAD_START_SP,
		fiq_return_handler);
	if (current_handler->resume)
		current_handler->resume(current_handler);
}
+3 −0
Original line number Diff line number Diff line
@@ -18,8 +18,11 @@ struct fiq_glue_handler {
	void (*fiq)(struct fiq_glue_handler *h, void *regs, void *svc_sp);
	void (*resume)(struct fiq_glue_handler *h);
};
typedef void (*fiq_return_handler_t)(void);

int fiq_glue_register_handler(struct fiq_glue_handler *handler);
int fiq_glue_set_return_handler(fiq_return_handler_t fiq_return);
int fiq_glue_clear_return_handler(fiq_return_handler_t fiq_return);

#ifdef CONFIG_FIQ_GLUE
void fiq_glue_resume(void);