0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 #include <linux/module.h>
0040 #include <linux/kernel.h>
0041 #include <linux/init.h>
0042 #include <linux/interrupt.h>
0043 #include <linux/seq_file.h>
0044
0045 #include <asm/cacheflush.h>
0046 #include <asm/cp15.h>
0047 #include <asm/fiq.h>
0048 #include <asm/irq.h>
0049 #include <asm/traps.h>
0050
0051 #define FIQ_OFFSET ({ \
0052 extern void *vector_fiq_offset; \
0053 (unsigned)&vector_fiq_offset; \
0054 })
0055
0056 static unsigned long dfl_fiq_insn;
0057 static struct pt_regs dfl_fiq_regs;
0058
0059
0060
0061
0062
0063 static int fiq_def_op(void *ref, int relinquish)
0064 {
0065 if (!relinquish) {
0066
0067 local_fiq_disable();
0068 set_fiq_regs(&dfl_fiq_regs);
0069 set_fiq_handler(&dfl_fiq_insn, sizeof(dfl_fiq_insn));
0070 local_fiq_enable();
0071
0072
0073 }
0074
0075 return 0;
0076 }
0077
0078 static struct fiq_handler default_owner = {
0079 .name = "default",
0080 .fiq_op = fiq_def_op,
0081 };
0082
0083 static struct fiq_handler *current_fiq = &default_owner;
0084
0085 int show_fiq_list(struct seq_file *p, int prec)
0086 {
0087 if (current_fiq != &default_owner)
0088 seq_printf(p, "%*s: %s\n", prec, "FIQ",
0089 current_fiq->name);
0090
0091 return 0;
0092 }
0093
0094 void set_fiq_handler(void *start, unsigned int length)
0095 {
0096 void *base = vectors_page;
0097 unsigned offset = FIQ_OFFSET;
0098
0099 memcpy(base + offset, start, length);
0100 if (!cache_is_vipt_nonaliasing())
0101 flush_icache_range((unsigned long)base + offset,
0102 (unsigned long)base + offset + length);
0103 flush_icache_range(0xffff0000 + offset, 0xffff0000 + offset + length);
0104 }
0105
0106 int claim_fiq(struct fiq_handler *f)
0107 {
0108 int ret = 0;
0109
0110 if (current_fiq) {
0111 ret = -EBUSY;
0112
0113 if (current_fiq->fiq_op != NULL)
0114 ret = current_fiq->fiq_op(current_fiq->dev_id, 1);
0115 }
0116
0117 if (!ret) {
0118 f->next = current_fiq;
0119 current_fiq = f;
0120 }
0121
0122 return ret;
0123 }
0124
0125 void release_fiq(struct fiq_handler *f)
0126 {
0127 if (current_fiq != f) {
0128 pr_err("%s FIQ trying to release %s FIQ\n",
0129 f->name, current_fiq->name);
0130 dump_stack();
0131 return;
0132 }
0133
0134 do
0135 current_fiq = current_fiq->next;
0136 while (current_fiq->fiq_op(current_fiq->dev_id, 0));
0137 }
0138
0139 static int fiq_start;
0140
0141 void enable_fiq(int fiq)
0142 {
0143 enable_irq(fiq + fiq_start);
0144 }
0145
0146 void disable_fiq(int fiq)
0147 {
0148 disable_irq(fiq + fiq_start);
0149 }
0150
0151 EXPORT_SYMBOL(set_fiq_handler);
0152 EXPORT_SYMBOL(__set_fiq_regs);
0153 EXPORT_SYMBOL(__get_fiq_regs);
0154 EXPORT_SYMBOL(claim_fiq);
0155 EXPORT_SYMBOL(release_fiq);
0156 EXPORT_SYMBOL(enable_fiq);
0157 EXPORT_SYMBOL(disable_fiq);
0158
0159 void __init init_FIQ(int start)
0160 {
0161 unsigned offset = FIQ_OFFSET;
0162 dfl_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
0163 get_fiq_regs(&dfl_fiq_regs);
0164 fiq_start = start;
0165 }