Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  linux/arch/arm/kernel/fiq.c
0004  *
0005  *  Copyright (C) 1998 Russell King
0006  *  Copyright (C) 1998, 1999 Phil Blundell
0007  *
0008  *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
0009  *
0010  *  FIQ support re-written by Russell King to be more generic
0011  *
0012  * We now properly support a method by which the FIQ handlers can
0013  * be stacked onto the vector.  We still do not support sharing
0014  * the FIQ vector itself.
0015  *
0016  * Operation is as follows:
0017  *  1. Owner A claims FIQ:
0018  *     - default_fiq relinquishes control.
0019  *  2. Owner A:
0020  *     - inserts code.
0021  *     - sets any registers,
0022  *     - enables FIQ.
0023  *  3. Owner B claims FIQ:
0024  *     - if owner A has a relinquish function.
0025  *       - disable FIQs.
0026  *       - saves any registers.
0027  *       - returns zero.
0028  *  4. Owner B:
0029  *     - inserts code.
0030  *     - sets any registers,
0031  *     - enables FIQ.
0032  *  5. Owner B releases FIQ:
0033  *     - Owner A is asked to reacquire FIQ:
0034  *   - inserts code.
0035  *   - restores saved registers.
0036  *   - enables FIQ.
0037  *  6. Goto 3
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 /* Default reacquire function
0060  * - we always relinquish FIQ control
0061  * - we always reacquire FIQ control
0062  */
0063 static int fiq_def_op(void *ref, int relinquish)
0064 {
0065     if (!relinquish) {
0066         /* Restore default handler and registers */
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         /* FIXME: notify irq controller to standard enable FIQs */
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);  /* defined in fiqasm.S */
0153 EXPORT_SYMBOL(__get_fiq_regs);  /* defined in fiqasm.S */
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 }