blob: 636528c9970aea9031ea8906bcfb9c570bdb859c [file] [log] [blame]
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_ARC_IRQFLAGS_H
#define __ASM_ARC_IRQFLAGS_H
#ifdef __KERNEL__
#include <asm/arcregs.h>
/******************************************************************
* IRQ Control Macros
******************************************************************/
/*
* Save IRQ state and disable IRQs
*/
#define local_irq_save(x) { x = _local_irq_save(); }
static inline long _local_irq_save(void) {
unsigned long temp, flags;
__asm__ __volatile__ (
"lr %1, [status32]\n\t"
"bic %0, %1, %2\n\t" // a BIC b = a AND ~b, but 4 byte insn instead of 8
"and.f 0, %1, %2 \n\t"
"flag.nz %0\n\t"
:"=r" (temp), "=r" (flags)
:"n" ((STATUS_E1_MASK | STATUS_E2_MASK))
:"cc", "memory"
);
return flags;
}
/*
* restore saved IRQ state
*/
static inline void local_irq_restore(unsigned long flags) {
__asm__ __volatile__ (
"flag %0\n\t"
:
:"r" (flags)
:"memory"
);
}
/*
* restore saved IRQ state and immediately sleep
*/
static inline void local_irq_restore_and_sleep(unsigned long flags) {
/*
* From ARC docs:
* Note that interrupts remain disabled until FLAG has completed its update
* of the flag registers in stage 4 of the ARCompact based pipeline. Hence,
* if SLEEP follows into the pipeline immediately behind FLAG, then no
* interrupt can be taken between the FLAG and SLEEP.
*/
__asm__ __volatile__ (
"flag %0\n\t"
"sleep\n\t"
:
:"r" (flags)
:"memory"
);
}
/*
* Conditionally Enable IRQs
*/
extern void local_irq_enable(void);
/*
* Unconditionally Disable IRQs
*/
static inline void local_irq_disable(void) {
unsigned long temp;
__asm__ __volatile__ (
"lr %0, [status32]\n\t"
"and %0, %0, %1\n\t" // {AND a,a,u7} is 4 byte so not conv to BIC
"flag %0\n\t"
:"=&r" (temp)
:"n" (~(STATUS_E1_MASK | STATUS_E2_MASK))
:"memory"
);
}
/*
* save IRQ state
*/
#define local_save_flags(x) { x = _local_save_flags(); }
static inline long _local_save_flags(void) {
unsigned long temp;
__asm__ __volatile__ (
"lr %0, [status32]\n\t"
:"=&r" (temp)
);
return temp;
}
/*
* mask/unmask an interrupt (@x = IRQ bitmap)
* e.g. to Disable IRQ 3 and 4, pass 0x18
*
* mask = disable IRQ = CLEAR bit in AUX_I_ENABLE
* unmask = enable IRQ = SET bit in AUX_I_ENABLE
*/
#define mask_interrupt(x) __asm__ __volatile__ ( \
"lr r20, [0x40c] \n\t" \
"and r20, r20, %0 \n\t" \
"sr r20,[0x40c] \n\t" \
: \
:"r" (~(x)) \
:"r20", "memory")
#define unmask_interrupt(x) __asm__ __volatile__ ( \
"lr r20, [0x40c] \n\t" \
"or r20, r20, %0 \n\t" \
"sr r20, [0x40c] \n\t" \
: \
:"r" (x) \
:"r20", "memory")
/*
* Query IRQ state
*/
static inline int irqs_disabled_flags(unsigned long flags)
{
return (!(flags & (STATUS_E1_MASK
#ifdef CONFIG_ARCH_ARC_LV2_INTR
| STATUS_E2_MASK
#endif
)));
}
static inline int irqs_disabled(void)
{
unsigned long flags;
local_save_flags(flags);
return (!(flags & (STATUS_E1_MASK
#ifdef CONFIG_ARCH_ARC_LV2_INTR
| STATUS_E2_MASK
#endif
)));
}
#endif
#endif