^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/arch/arm/kernel/fiq.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 1998 Russell King
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 1998, 1999 Phil Blundell
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * FIQ support re-written by Russell King to be more generic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * We now properly support a method by which the FIQ handlers can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * be stacked onto the vector. We still do not support sharing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * the FIQ vector itself.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Operation is as follows:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * 1. Owner A claims FIQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * - default_fiq relinquishes control.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * 2. Owner A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * - inserts code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * - sets any registers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * - enables FIQ.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * 3. Owner B claims FIQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * - if owner A has a relinquish function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * - disable FIQs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * - saves any registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * - returns zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * 4. Owner B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * - inserts code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * - sets any registers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * - enables FIQ.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * 5. Owner B releases FIQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * - Owner A is asked to reacquire FIQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * - inserts code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * - restores saved registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * - enables FIQ.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * 6. Goto 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <asm/cp15.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <asm/fiq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #include <asm/traps.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define FIQ_OFFSET ({ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) extern void *vector_fiq_offset; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) (unsigned)&vector_fiq_offset; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static unsigned long dfl_fiq_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static struct pt_regs dfl_fiq_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /* Default reacquire function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * - we always relinquish FIQ control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * - we always reacquire FIQ control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static int fiq_def_op(void *ref, int relinquish)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!relinquish) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /* Restore default handler and registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) local_fiq_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) set_fiq_regs(&dfl_fiq_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) set_fiq_handler(&dfl_fiq_insn, sizeof(dfl_fiq_insn));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) local_fiq_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* FIXME: notify irq controller to standard enable FIQs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static struct fiq_handler default_owner = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .name = "default",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .fiq_op = fiq_def_op,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static struct fiq_handler *current_fiq = &default_owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int show_fiq_list(struct seq_file *p, int prec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (current_fiq != &default_owner)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) seq_printf(p, "%*s: %s\n", prec, "FIQ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) current_fiq->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) void set_fiq_handler(void *start, unsigned int length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) void *base = vectors_page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) unsigned int volatile offset = FIQ_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) offset &= 0xfffffffc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) memcpy(base + offset, start, length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (!cache_is_vipt_nonaliasing())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) flush_icache_range((unsigned long)base + offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) (unsigned long)base + offset + length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) flush_icache_range(0xffff0000 + offset, 0xffff0000 + offset + length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) int claim_fiq(struct fiq_handler *f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (current_fiq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (current_fiq->fiq_op != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) ret = current_fiq->fiq_op(current_fiq->dev_id, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) f->next = current_fiq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) current_fiq = f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) void release_fiq(struct fiq_handler *f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (current_fiq != f) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) pr_err("%s FIQ trying to release %s FIQ\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) f->name, current_fiq->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) dump_stack();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) current_fiq = current_fiq->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) while (current_fiq->fiq_op(current_fiq->dev_id, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static int fiq_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) void enable_fiq(int fiq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) enable_irq(fiq + fiq_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) void disable_fiq(int fiq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) disable_irq(fiq + fiq_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) EXPORT_SYMBOL(set_fiq_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) EXPORT_SYMBOL(__get_fiq_regs); /* defined in fiqasm.S */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) EXPORT_SYMBOL(claim_fiq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) EXPORT_SYMBOL(release_fiq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) EXPORT_SYMBOL(enable_fiq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) EXPORT_SYMBOL(disable_fiq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) void __init init_FIQ(int start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) unsigned offset = FIQ_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) dfl_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) get_fiq_regs(&dfl_fiq_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) fiq_start = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }