2 * linux/arch/arm/kernel/fiq.c
4 * Copyright (C) 1998 Russell King
5 * Copyright (C) 1998, 1999 Phil Blundell
7 * FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
9 * FIQ support re-written by Russell King to be more generic
11 * We now properly support a method by which the FIQ handlers can
12 * be stacked onto the vector. We still do not support sharing
13 * the FIQ vector itself.
15 * Operation is as follows:
16 * 1. Owner A claims FIQ:
17 * - default_fiq relinquishes control.
20 * - sets any registers,
22 * 3. Owner B claims FIQ:
23 * - if owner A has a relinquish function.
25 * - saves any registers.
29 * - sets any registers,
31 * 5. Owner B releases FIQ:
32 * - Owner A is asked to reacquire FIQ:
34 * - restores saved registers.
38 #include <linux/config.h>
40 #include <linux/mman.h>
41 #include <linux/init.h>
45 #include <asm/pgalloc.h>
46 #include <asm/system.h>
47 #include <asm/uaccess.h>
49 #define FIQ_VECTOR 0x1c
51 static unsigned long no_fiq_insn;
54 static inline void unprotect_page_0(void)
56 modify_domain(DOMAIN_USER, DOMAIN_MANAGER);
59 static inline void protect_page_0(void)
61 modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
65 #define unprotect_page_0()
66 #define protect_page_0()
70 /* Default reacquire function
71 * - we always relinquish FIQ control
72 * - we always reacquire FIQ control
74 int fiq_def_op(void *ref, int relinquish)
78 *(unsigned long *)FIQ_VECTOR = no_fiq_insn;
80 flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + 4);
86 static struct fiq_handler default_owner = {
91 static struct fiq_handler *current_fiq = &default_owner;
93 int get_fiq_list(char *buf)
97 if (current_fiq != &default_owner)
98 p += sprintf(p, "FIQ: %s\n",
104 void set_fiq_handler(void *start, unsigned int length)
108 memcpy((void *)FIQ_VECTOR, start, length);
111 flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + length);
115 * Taking an interrupt in FIQ mode is death, so both these functions
116 * disable irqs for the duration.
118 void set_fiq_regs(struct pt_regs *regs)
120 register unsigned long tmp, tmp2;
125 orr %1, %1, #0x0c000001
126 teqp %1, #0 @ select FIQ mode
129 teqp %0, #0 @ return to SVC mode
135 msr cpsr_c, %1 @ select FIQ mode
138 msr cpsr_c, %0 @ return to SVC mode
141 : "=&r" (tmp), "=&r" (tmp2)
142 : "r" (®s->ARM_r8)
143 /* These registers aren't modified by the above code in a way
144 visible to the compiler, but we mark them as clobbers anyway
145 so that GCC won't put any of the input or output operands in
147 : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
150 void get_fiq_regs(struct pt_regs *regs)
152 register unsigned long tmp, tmp2;
157 orr %1, %1, #0x0c000001
158 teqp %1, #0 @ select FIQ mode
161 teqp %0, #0 @ return to SVC mode
167 msr cpsr_c, %1 @ select FIQ mode
170 msr cpsr_c, %0 @ return to SVC mode
173 : "=&r" (tmp), "=&r" (tmp2)
174 : "r" (®s->ARM_r8)
175 /* These registers aren't modified by the above code in a way
176 visible to the compiler, but we mark them as clobbers anyway
177 so that GCC won't put any of the input or output operands in
179 : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
182 int claim_fiq(struct fiq_handler *f)
189 if (current_fiq->fiq_op != NULL)
190 ret = current_fiq->fiq_op(current_fiq->dev_id, 1);
194 f->next = current_fiq;
201 void release_fiq(struct fiq_handler *f)
203 if (current_fiq != f) {
204 printk(KERN_ERR "%s FIQ trying to release %s FIQ\n",
205 f->name, current_fiq->name);
206 #ifdef CONFIG_DEBUG_ERRORS
213 current_fiq = current_fiq->next;
214 while (current_fiq->fiq_op(current_fiq->dev_id, 0));
217 void __init init_FIQ(void)
219 no_fiq_insn = *(unsigned long *)FIQ_VECTOR;