/*------------------------------------------------------------------------------------------*\ * * Copyright (C) 2016 AVM GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \*------------------------------------------------------------------------------------------*/ #ifndef _AVM_FIQ_H_ #define _AVM_FIQ_H_ #include #include #include #include /* * Zaehler fuer spurious interrupts, pro CPU ... */ DECLARE_PER_CPU(unsigned int, spurious_count); /** * Mode-Umschaltung */ #define AVM_CHANGE_MODE(_mode) \ do { \ asm volatile( \ "nop \n" \ "nop \n" \ "nop \n" \ "nop \n" \ "nop \n" \ "nop \n" \ "nop \n" \ "mrs r0, cpsr \n" \ "bic r0, r0, #31 \n" \ "orr r0, r0, %[mode] \n" \ "msr cpsr_c, r0 \n" \ "nop \n" \ "nop \n" \ "nop \n" \ "nop \n" \ "nop \n" \ "nop \n" \ "nop \n" \ : \ : [mode] "n"(_mode) \ : "memory", "cc", "r0" \ ); \ } while (0) /*--------------------------------------------------------------------------------*\ * \brief: Sind wir im FIQ? * ret: Nein: 0 * Ja: 1 \*--------------------------------------------------------------------------------*/ static inline int is_cpu_mode_fiq(void) { unsigned long cpsr_reg; asm volatile( " mrs %0, cpsr @ is_cpu_mode_fiq\n" : "=r" (cpsr_reg) : : "memory", "cc"); return (cpsr_reg & MODE_MASK) == FIQ_MODE; } /**--------------------------------------------------------------------------------**\ * \brief: Status sichern, dann FIRQ ausschalten \**--------------------------------------------------------------------------------**/ static inline unsigned long avm_arch_local_fiq_save(void) { unsigned long flags; asm volatile( " mrs %0, cpsr @ avm_arch_local_fiq_save\n" " cpsid f" : "=r" (flags) : : "memory", "cc"); return flags; } /**--------------------------------------------------------------------------------**\ * \brief: IRQ/FIQ-Enable entsprechend flags setzen \**--------------------------------------------------------------------------------**/ static inline void avm_arch_local_fiq_restore(unsigned long flags) { asm volatile( " msr cpsr_c, %0 @ avm_arch_local_irq_restore" : : "r" (flags) : "memory", "cc"); } /**--------------------------------------------------------------------------------**\ * \brief: Statuts sichern und dann IRQ und FIRQ auschalten \**--------------------------------------------------------------------------------**/ static inline unsigned long avm_arch_local_fiq_and_iq_save(void) { unsigned long flags; asm volatile( " mrs %0, cpsr @ avm_arch_local_fiq_and_iq_save\n" " cpsid fi" : "=r" (flags) : : "memory", "cc"); return flags; } /**--------------------------------------------------------------------------------**\ * \brief: IRQ und FIRQ anschalten \**--------------------------------------------------------------------------------**/ static inline void avm_arch_local_fiq_and_iq_enable(void) { asm volatile( " cpsie fi @ avm_arch_local_fiq_and_iq_enable" : : : "memory", "cc"); } /**--------------------------------------------------------------------------------**\ * \brief: FIQ belegen * \param: cpu * \param: irq * \param: handler * \param: fiqflags * \param: devname * \param: dev_id * * ret: Ungültige CPU-Nr: -EINVAL * Bereits belegt: -EBUSY * Sonst 0 \**--------------------------------------------------------------------------------**/ typedef irqreturn_t (*avm_fiq_cb_t)(int, void *); int avm_request_fiq_on(const struct cpumask *cpumask, unsigned int irq, avm_fiq_cb_t handler, unsigned long fiqflags, const char *devname, void *dev_id); /*--------------------------------------------------------------------------------*\ * \brief: FIQ freigeben * \param: cpu * \param: irq * \param: dev_id - muss mit der in avm_request_fiq_on() angegebenen uebereinstimmen * ret: Ungültige CPU-Nr: -EINVAL * Unpassende Ref: -EINVAL * Sonst 0 \*--------------------------------------------------------------------------------*/ int avm_free_fiq_on(int cpu, unsigned int irq, void *dev_id); /**--------------------------------------------------------------------------------**\ * \brief: Belegten FIQ einschalten * \param: cpu * \param: irq * ret: War nicht korrekt angefordert: -EINVAL * Sonst 0 \**--------------------------------------------------------------------------------**/ int avm_enable_fiq_on(int cpu, unsigned int irq); /**--------------------------------------------------------------------------------**\ * \brief: Belegten FIQ ausschalten * \param: cpu * \param: irq * ret: War nicht korrekt angefordert: -EINVAL * Sonst 0 \**--------------------------------------------------------------------------------**/ int avm_disable_fiq_on(int cpu, unsigned int irq); /**--------------------------------------------------------------------------------**\ * \brief: falls in Exception aus FIQ-Kontext, kann hiermit regs um die korrekten banked * Register korrigiert werden \**--------------------------------------------------------------------------------**/ void copy_banked_fiqregs(struct pt_regs *regs); /**--------------------------------------------------------------------------------**\ * \brief: Lese banked register aus FIQ-Kontext * nur sp und lr * diese Funktion nur aus FIQ-Kontext verwenden \**--------------------------------------------------------------------------------**/ void copy_banked_regs(struct pt_regs *regs, const struct pt_regs *org_regs); /**--------------------------------------------------------------------------------**\ * \brief: Lese alle banked register aus FIQ-Kontext * diese Funktion nur aus FIQ-Kontext verwenden \**--------------------------------------------------------------------------------**/ void copy_banked_regs_full(struct pt_regs *regs, const struct pt_regs *org_regs); /*--------------------------------------------------------------------------------*\ \brief: liefere den SP im SVC als Grundlage fuer Ermittlung des current dieser CPU diese Funktion nur aus FIQ-Kontext verwenden \*--------------------------------------------------------------------------------*/ unsigned long get_svc_sp(void); /**--------------------------------------------------------------------------------**\ \brief: Backtrace aller CPU's ueber den FAST-IRQ \param: exception_context falls Ausgabe aus Exception passiert (sonst i.d.R. ueberfluessiger Backtrace des Exceptionhandlers) \**--------------------------------------------------------------------------------**/ bool avm_trigger_all_cpu_backtrace(struct pt_regs *exception_regs, cpumask_t *cpu_mask); /* * Per-cpu current frame pointer - the location of the last exception frame on * the stack */ DECLARE_PER_CPU(struct pt_regs *, __fiq_regs); /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static inline struct pt_regs *get_fiq_regs(void) { return __this_cpu_read(__fiq_regs); } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static inline struct pt_regs *set_fiq_regs(struct pt_regs *new_regs) { struct pt_regs *old_regs; old_regs = __this_cpu_read(__fiq_regs); __this_cpu_write(__fiq_regs, new_regs); return old_regs; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static inline struct thread_info *thread_info_by_sp(unsigned long sp) { return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); } #if defined(CONFIG_PROC_FS) void avm_fiq_dump_stat(void); #else /*--- #if defined(CONFIG_PROC_FS) ---*/ #define avm_fiq_dump_stat() #endif /*--- #else ---*//*--- #if defined(CONFIG_PROC_FS) ---*/ #endif // #ifndef _AVM_FIQ_H_