irq_smp.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
- /*
- * linux/arch/alpha/kernel/irq_smp.c
- *
- */
- #include <linux/kernel.h>
- #include <linux/signal.h>
- #include <linux/sched.h>
- #include <linux/interrupt.h>
- #include <linux/random.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <linux/irq.h>
- #include <asm/system.h>
- #include <asm/io.h>
- /* Who has global_irq_lock. */
- int global_irq_holder = NO_PROC_ID;
- /* This protects IRQ's. */
- spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
- /* Global IRQ locking depth. */
- static void *previous_irqholder = NULL;
- #define MAXCOUNT 100000000
- static void
- show(char * str, void *where)
- {
- #if 0
- int i;
- unsigned long *stack;
- #endif
- int cpu = smp_processor_id();
- printk("n%s, CPU %d: %pn", str, cpu, where);
- printk("irq: %d [%d %d]n",
- irqs_running(),
- local_irq_count(0),
- local_irq_count(1));
- printk("bh: %d [%d %d]n",
- spin_is_locked(&global_bh_lock) ? 1 : 0,
- local_bh_count(0),
- local_bh_count(1));
- #if 0
- stack = (unsigned long *) &str;
- for (i = 40; i ; i--) {
- unsigned long x = *++stack;
- if (x > (unsigned long) &init_task_union &&
- x < (unsigned long) &vsprintf) {
- printk("<[%08lx]> ", x);
- }
- }
- #endif
- }
- static inline void
- wait_on_irq(int cpu, void *where)
- {
- int count = MAXCOUNT;
- for (;;) {
- /*
- * Wait until all interrupts are gone. Wait
- * for bottom half handlers unless we're
- * already executing in one..
- */
- if (!irqs_running()) {
- if (local_bh_count(cpu)
- || !spin_is_locked(&global_bh_lock))
- break;
- }
- /* Duh, we have to loop. Release the lock to avoid deadlocks */
- spin_unlock(&global_irq_lock);
- for (;;) {
- if (!--count) {
- show("wait_on_irq", where);
- count = MAXCOUNT;
- }
- __sti();
- udelay(1); /* make sure to run pending irqs */
- __cli();
- if (irqs_running())
- continue;
- if (spin_is_locked(&global_irq_lock))
- continue;
- if (!local_bh_count(cpu)
- && spin_is_locked(&global_bh_lock))
- continue;
- if (spin_trylock(&global_irq_lock))
- break;
- }
- }
- }
- static inline void
- get_irqlock(int cpu, void* where)
- {
- if (!spin_trylock(&global_irq_lock)) {
- /* Do we already hold the lock? */
- if (cpu == global_irq_holder)
- return;
- /* Uhhuh.. Somebody else got it. Wait. */
- spin_lock(&global_irq_lock);
- }
- /*
- * Ok, we got the lock bit.
- * But that's actually just the easy part.. Now
- * we need to make sure that nobody else is running
- * in an interrupt context.
- */
- wait_on_irq(cpu, where);
- /*
- * Finally.
- */
- #ifdef CONFIG_DEBUG_SPINLOCK
- global_irq_lock.task = current;
- global_irq_lock.previous = where;
- #endif
- global_irq_holder = cpu;
- previous_irqholder = where;
- }
- void
- __global_cli(void)
- {
- int cpu = smp_processor_id();
- void *where = __builtin_return_address(0);
- /*
- * Maximize ipl. If ipl was previously 0 and if this thread
- * is not in an irq, then take global_irq_lock.
- */
- if (swpipl(IPL_MAX) == IPL_MIN && !local_irq_count(cpu))
- get_irqlock(cpu, where);
- }
- void
- __global_sti(void)
- {
- int cpu = smp_processor_id();
- if (!local_irq_count(cpu))
- release_irqlock(cpu);
- __sti();
- }
- /*
- * SMP flags value to restore to:
- * 0 - global cli
- * 1 - global sti
- * 2 - local cli
- * 3 - local sti
- */
- unsigned long
- __global_save_flags(void)
- {
- int retval;
- int local_enabled;
- unsigned long flags;
- int cpu = smp_processor_id();
- __save_flags(flags);
- local_enabled = (!(flags & 7));
- /* default to local */
- retval = 2 + local_enabled;
- /* Check for global flags if we're not in an interrupt. */
- if (!local_irq_count(cpu)) {
- if (local_enabled)
- retval = 1;
- if (global_irq_holder == cpu)
- retval = 0;
- }
- return retval;
- }
- void
- __global_restore_flags(unsigned long flags)
- {
- switch (flags) {
- case 0:
- __global_cli();
- break;
- case 1:
- __global_sti();
- break;
- case 2:
- __cli();
- break;
- case 3:
- __sti();
- break;
- default:
- printk(KERN_ERR "global_restore_flags: %08lx (%p)n",
- flags, __builtin_return_address(0));
- }
- }
- /*
- * From its use, I infer that synchronize_irq() stalls a thread until
- * the effects of a command to an external device are known to have
- * taken hold. Typically, the command is to stop sending interrupts.
- * The strategy here is wait until there is at most one processor
- * (this one) in an irq. The memory barrier serializes the write to
- * the device and the subsequent accesses of global_irq_count.
- * --jmartin
- */
- #define DEBUG_SYNCHRONIZE_IRQ 0
- void
- synchronize_irq(void)
- {
- #if 0
- /* Joe's version. */
- int cpu = smp_processor_id();
- int local_count;
- int global_count;
- int countdown = 1<<24;
- void *where = __builtin_return_address(0);
- mb();
- do {
- local_count = local_irq_count(cpu);
- global_count = atomic_read(&global_irq_count);
- if (DEBUG_SYNCHRONIZE_IRQ && (--countdown == 0)) {
- printk("%d:%d/%dn", cpu, local_count, global_count);
- show("synchronize_irq", where);
- break;
- }
- } while (global_count != local_count);
- #else
- /* Jay's version. */
- if (irqs_running()) {
- cli();
- sti();
- }
- #endif
- }