📄 irq.c
字号:
/* irq.c: FRV IRQ handling * * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * 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. *//* * (mostly architecture independent, will move to kernel/irq.c in 2.5.) * * IRQs are in fact implemented a bit like signal handlers for the kernel. * Naturally it's not a 1:1 relation, but there are similarities. */#include <linux/config.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <linux/timex.h>#include <linux/slab.h>#include <linux/random.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <linux/kernel_stat.h>#include <linux/irq.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <asm/atomic.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include <asm/pgalloc.h>#include <asm/delay.h>#include <asm/irq.h>#include <asm/irc-regs.h>#include <asm/irq-routing.h>#include <asm/gdb-stub.h>extern void __init fpga_init(void);extern void __init route_mb93493_irqs(void);static void register_irq_proc (unsigned int irq);/* * Special irq handlers. */irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) { return IRQ_HANDLED; }atomic_t irq_err_count;/* * Generic, controller-independent functions: */int show_interrupts(struct seq_file *p, void *v){ struct irqaction *action; struct irq_group *group; unsigned long flags; int level, grp, ix, i, j; i = *(loff_t *) v; switch (i) { case 0: seq_printf(p, " "); for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) seq_printf(p, "CPU%d ",j); seq_putc(p, '\n'); break; case 1 ... NR_IRQ_GROUPS * NR_IRQ_ACTIONS_PER_GROUP: local_irq_save(flags); grp = (i - 1) / NR_IRQ_ACTIONS_PER_GROUP; group = irq_groups[grp]; if (!group) goto skip; ix = (i - 1) % NR_IRQ_ACTIONS_PER_GROUP; action = group->actions[ix]; if (!action) goto skip; seq_printf(p, "%3d: ", i - 1);#ifndef CONFIG_SMP seq_printf(p, "%10u ", kstat_irqs(i));#else for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) seq_printf(p, "%10u ", kstat_cpu(j).irqs[i - 1]);#endif level = group->sources[ix]->level - frv_irq_levels; seq_printf(p, " %12s@%x", group->sources[ix]->muxname, level); seq_printf(p, " %s", action->name); for (action = action->next; action; action = action->next) seq_printf(p, ", %s", action->name); seq_putc(p, '\n');skip: local_irq_restore(flags); break; case NR_IRQ_GROUPS * NR_IRQ_ACTIONS_PER_GROUP + 1: seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); break; default: break; } return 0;}/* * Generic enable/disable code: this just calls * down into the PIC-specific version for the actual * hardware disable after having gotten the irq * controller lock. *//** * disable_irq_nosync - disable an irq without waiting * @irq: Interrupt to disable * * Disable the selected interrupt line. Disables and Enables are * nested. * Unlike disable_irq(), this function does not ensure existing * instances of the IRQ handler have completed before returning. * * This function may be called from IRQ context. */void disable_irq_nosync(unsigned int irq){ struct irq_source *source; struct irq_group *group; struct irq_level *level; unsigned long flags; int idx = irq & (NR_IRQ_ACTIONS_PER_GROUP - 1); group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; if (!group) BUG(); source = group->sources[idx]; if (!source) BUG(); level = source->level; spin_lock_irqsave(&level->lock, flags); if (group->control) { if (!group->disable_cnt[idx]++) group->control(group, idx, 0); } else if (!level->disable_count++) { __set_MASK(level - frv_irq_levels); } spin_unlock_irqrestore(&level->lock, flags);}/** * disable_irq - disable an irq and wait for completion * @irq: Interrupt to disable * * Disable the selected interrupt line. Enables and Disables are * nested. * This function waits for any pending IRQ handlers for this interrupt * to complete before returning. If you use this function while * holding a resource the IRQ handler may need you will deadlock. * * This function may be called - with care - from IRQ context. */void disable_irq(unsigned int irq){ disable_irq_nosync(irq);#ifdef CONFIG_SMP if (!local_irq_count(smp_processor_id())) { do { barrier(); } while (irq_desc[irq].status & IRQ_INPROGRESS); }#endif}/** * enable_irq - enable handling of an irq * @irq: Interrupt to enable * * Undoes the effect of one call to disable_irq(). If this * matches the last disable, processing of interrupts on this * IRQ line is re-enabled. * * This function may be called from IRQ context. */void enable_irq(unsigned int irq){ struct irq_source *source; struct irq_group *group; struct irq_level *level; unsigned long flags; int idx = irq & (NR_IRQ_ACTIONS_PER_GROUP - 1); int count; group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; if (!group) BUG(); source = group->sources[idx]; if (!source) BUG(); level = source->level; spin_lock_irqsave(&level->lock, flags); if (group->control) count = group->disable_cnt[idx]; else count = level->disable_count; switch (count) { case 1: if (group->control) { if (group->actions[idx]) group->control(group, idx, 1); } else { if (level->usage) __clr_MASK(level - frv_irq_levels); } /* fall-through */ default: count--; break; case 0: printk("enable_irq(%u) unbalanced from %p\n", irq, __builtin_return_address(0)); } if (group->control) group->disable_cnt[idx] = count; else level->disable_count = count; spin_unlock_irqrestore(&level->lock, flags);}/*****************************************************************************//* * handles all normal device IRQ's * - registers are referred to by the __frame variable (GR28) * - IRQ distribution is complicated in this arch because of the many PICs, the * way they work and the way they cascade */asmlinkage void do_IRQ(void){ struct irq_source *source; int level, cpu; level = (__frame->tbr >> 4) & 0xf; cpu = smp_processor_id();#if 0 { static u32 irqcount; *(volatile u32 *) 0xe1200004 = ~((irqcount++ << 8) | level); *(volatile u16 *) 0xffc00100 = (u16) ~0x9999; mb(); }#endif if ((unsigned long) __frame - (unsigned long) (current + 1) < 512) BUG(); __set_MASK(level); __clr_RC(level); __clr_IRL(); kstat_this_cpu.irqs[level]++; irq_enter(); for (source = frv_irq_levels[level].sources; source; source = source->next) source->doirq(source); irq_exit(); __clr_MASK(level); /* only process softirqs if we didn't interrupt another interrupt handler */ if ((__frame->psr & PSR_PIL) == PSR_PIL_0) if (local_softirq_pending()) do_softirq();#ifdef CONFIG_PREEMPT local_irq_disable(); while (--current->preempt_count == 0) { if (!(__frame->psr & PSR_S) || current->need_resched == 0 || in_interrupt()) break; current->preempt_count++; local_irq_enable(); preempt_schedule(); local_irq_disable(); }#endif#if 0 { *(volatile u16 *) 0xffc00100 = (u16) ~0x6666; mb(); }#endif} /* end do_IRQ() *//*****************************************************************************//* * handles all NMIs when not co-opted by the debugger * - registers are referred to by the __frame variable (GR28) */asmlinkage void do_NMI(void){} /* end do_NMI() *//*****************************************************************************//** * request_irq - allocate an interrupt line * @irq: Interrupt line to allocate * @handler: Function to be called when the IRQ occurs * @irqflags: Interrupt type flags * @devname: An ascii name for the claiming device * @dev_id: A cookie passed back to the handler function * * This call allocates interrupt resources and enables the * interrupt line and IRQ handling. From the point this * call is made your handler function may be invoked. Since * your handler function must clear any interrupt the board * raises, you must take care both to initialise your hardware * and to set up the interrupt handler in the right order. * * Dev_id must be globally unique. Normally the address of the * device data structure is used as the cookie. Since the handler * receives this value it makes sense to use it. * * If your interrupt is shared you must pass a non NULL dev_id * as this is required when freeing the interrupt. * * Flags: * * SA_SHIRQ Interrupt is shared * * SA_INTERRUPT Disable local interrupts while processing * * SA_SAMPLE_RANDOM The interrupt can be used for entropy * */int request_irq(unsigned int irq,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -