This commit was generated by cvs2svn to compensate for changes in r517,
[linux-2.6.git] / arch / arm / kernel / fiq.c
1 /*
2  *  linux/arch/arm/kernel/fiq.c
3  *
4  *  Copyright (C) 1998 Russell King
5  *  Copyright (C) 1998, 1999 Phil Blundell
6  *
7  *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
8  *
9  *  FIQ support re-written by Russell King to be more generic
10  *
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.
14  *
15  * Operation is as follows:
16  *  1. Owner A claims FIQ:
17  *     - default_fiq relinquishes control.
18  *  2. Owner A:
19  *     - inserts code.
20  *     - sets any registers,
21  *     - enables FIQ.
22  *  3. Owner B claims FIQ:
23  *     - if owner A has a relinquish function.
24  *       - disable FIQs.
25  *       - saves any registers.
26  *       - returns zero.
27  *  4. Owner B:
28  *     - inserts code.
29  *     - sets any registers,
30  *     - enables FIQ.
31  *  5. Owner B releases FIQ:
32  *     - Owner A is asked to reacquire FIQ:
33  *       - inserts code.
34  *       - restores saved registers.
35  *       - enables FIQ.
36  *  6. Goto 3
37  */
38 #include <linux/module.h>
39 #include <linux/kernel.h>
40 #include <linux/init.h>
41 #include <linux/seq_file.h>
42
43 #include <asm/cacheflush.h>
44 #include <asm/fiq.h>
45 #include <asm/irq.h>
46 #include <asm/system.h>
47 #include <asm/uaccess.h>
48
49 static unsigned long no_fiq_insn;
50
51 /* Default reacquire function
52  * - we always relinquish FIQ control
53  * - we always reacquire FIQ control
54  */
55 static int fiq_def_op(void *ref, int relinquish)
56 {
57         if (!relinquish)
58                 set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
59
60         return 0;
61 }
62
63 static struct fiq_handler default_owner = {
64         .name   = "default",
65         .fiq_op = fiq_def_op,
66 };
67
68 static struct fiq_handler *current_fiq = &default_owner;
69
70 int show_fiq_list(struct seq_file *p, void *v)
71 {
72         if (current_fiq != &default_owner)
73                 seq_printf(p, "FIQ:              %s\n", current_fiq->name);
74
75         return 0;
76 }
77
78 void set_fiq_handler(void *start, unsigned int length)
79 {
80         memcpy((void *)0xffff001c, start, length);
81         flush_icache_range(0xffff001c, 0xffff001c + length);
82         if (!vectors_high())
83                 flush_icache_range(0x1c, 0x1c + length);
84 }
85
86 /*
87  * Taking an interrupt in FIQ mode is death, so both these functions
88  * disable irqs for the duration. 
89  */
90 void set_fiq_regs(struct pt_regs *regs)
91 {
92         register unsigned long tmp, tmp2;
93         __asm__ volatile (
94         "mrs    %0, cpsr\n\
95         mov     %1, %3\n\
96         msr     cpsr_c, %1      @ select FIQ mode\n\
97         mov     r0, r0\n\
98         ldmia   %2, {r8 - r14}\n\
99         msr     cpsr_c, %0      @ return to SVC mode\n\
100         mov     r0, r0"
101         : "=&r" (tmp), "=&r" (tmp2)
102         : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)
103         /* These registers aren't modified by the above code in a way
104            visible to the compiler, but we mark them as clobbers anyway
105            so that GCC won't put any of the input or output operands in
106            them.  */
107         : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
108 }
109
110 void get_fiq_regs(struct pt_regs *regs)
111 {
112         register unsigned long tmp, tmp2;
113         __asm__ volatile (
114         "mrs    %0, cpsr\n\
115         mov     %1, %3\n\
116         msr     cpsr_c, %1      @ select FIQ mode\n\
117         mov     r0, r0\n\
118         stmia   %2, {r8 - r14}\n\
119         msr     cpsr_c, %0      @ return to SVC mode\n\
120         mov     r0, r0"
121         : "=&r" (tmp), "=&r" (tmp2)
122         : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)
123         /* These registers aren't modified by the above code in a way
124            visible to the compiler, but we mark them as clobbers anyway
125            so that GCC won't put any of the input or output operands in
126            them.  */
127         : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
128 }
129
130 int claim_fiq(struct fiq_handler *f)
131 {
132         int ret = 0;
133
134         if (current_fiq) {
135                 ret = -EBUSY;
136
137                 if (current_fiq->fiq_op != NULL)
138                         ret = current_fiq->fiq_op(current_fiq->dev_id, 1);
139         }
140
141         if (!ret) {
142                 f->next = current_fiq;
143                 current_fiq = f;
144         }
145
146         return ret;
147 }
148
149 void release_fiq(struct fiq_handler *f)
150 {
151         if (current_fiq != f) {
152                 printk(KERN_ERR "%s FIQ trying to release %s FIQ\n",
153                        f->name, current_fiq->name);
154                 dump_stack();
155                 return;
156         }
157
158         do
159                 current_fiq = current_fiq->next;
160         while (current_fiq->fiq_op(current_fiq->dev_id, 0));
161 }
162
163 void enable_fiq(int fiq)
164 {
165         enable_irq(fiq + FIQ_START);
166 }
167
168 void disable_fiq(int fiq)
169 {
170         disable_irq(fiq + FIQ_START);
171 }
172
173 EXPORT_SYMBOL(set_fiq_handler);
174 EXPORT_SYMBOL(set_fiq_regs);
175 EXPORT_SYMBOL(get_fiq_regs);
176 EXPORT_SYMBOL(claim_fiq);
177 EXPORT_SYMBOL(release_fiq);
178 EXPORT_SYMBOL(enable_fiq);
179 EXPORT_SYMBOL(disable_fiq);
180
181 void __init init_FIQ(void)
182 {
183         no_fiq_insn = *(unsigned long *)0xffff001c;
184 }