⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irq.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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 + -