irq.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 718 行 · 第 1/2 页

C
718
字号
	if (i == 0) {		seq_puts(p, "           ");		for (j=0; j<NR_CPUS; j++)			if (cpu_online(j))				seq_printf(p, "CPU%d       ", j);		seq_putc(p, '\n');	}	if (i < NR_IRQS) {		spin_lock_irqsave(&irq_desc[i].lock, flags);		action = irq_desc[i].action;		if ( !action || !action->handler )			goto skip;		seq_printf(p, "%3d: ", i);#ifdef CONFIG_SMP		for (j = 0; j < NR_CPUS; j++)			if (cpu_online(j))				seq_printf(p, "%10u ",					   kstat_cpu(j).irqs[i]);#else		seq_printf(p, "%10u ", kstat_irqs(i));#endif /* CONFIG_SMP */		if (irq_desc[i].handler)			seq_printf(p, " %s ", irq_desc[i].handler->typename);		else			seq_puts(p, "  None      ");		seq_printf(p, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge  ");		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:		spin_unlock_irqrestore(&irq_desc[i].lock, flags);	} else if (i == NR_IRQS) {#ifdef CONFIG_TAU_INT		if (tau_initialized){			seq_puts(p, "TAU: ");			for (j = 0; j < NR_CPUS; j++)				if (cpu_online(j))					seq_printf(p, "%10u ", tau_interrupts(j));			seq_puts(p, "  PowerPC             Thermal Assist (cpu temp)\n");		}#endif#ifdef CONFIG_SMP		/* should this be per processor send/receive? */		seq_printf(p, "IPI (recv/sent): %10u/%u\n",				atomic_read(&ipi_recv), atomic_read(&ipi_sent));#endif		seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts);	}	return 0;}static inline voidhandle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action){	int status = 0;	if (!(action->flags & SA_INTERRUPT))		local_irq_enable();	do {		status |= action->flags;		action->handler(irq, action->dev_id, regs);		action = action->next;	} while (action);	if (status & SA_SAMPLE_RANDOM)		add_interrupt_randomness(irq);	local_irq_disable();}/* * Eventually, this should take an array of interrupts and an array size * so it can dispatch multiple interrupts. */void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq){	int status;	struct irqaction *action;	irq_desc_t *desc = irq_desc + irq;	kstat_this_cpu.irqs[irq]++;	spin_lock(&desc->lock);	ack_irq(irq);	/*	   REPLAY is when Linux resends an IRQ that was dropped earlier	   WAITING is used by probe to mark irqs that are being tested	   */	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);	if (!(status & IRQ_PER_CPU))		status |= IRQ_PENDING; /* we _want_ to handle it */	/*	 * If the IRQ is disabled for whatever reason, we cannot	 * use the action we have.	 */	action = NULL;	if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {		action = desc->action;		if (!action || !action->handler) {			ppc_spurious_interrupts++;			printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq);			/* We can't call disable_irq here, it would deadlock */			++desc->depth;			desc->status |= IRQ_DISABLED;			mask_irq(irq);			/* This is a real interrupt, we have to eoi it,			   so we jump to out */			goto out;		}		status &= ~IRQ_PENDING; /* we commit to handling */		if (!(status & IRQ_PER_CPU))			status |= IRQ_INPROGRESS; /* we are handling it */	}	desc->status = status;	/*	 * If there is no IRQ handler or it was disabled, exit early.	   Since we set PENDING, if another processor is handling	   a different instance of this same irq, the other processor	   will take care of it.	 */	if (unlikely(!action))		goto out;	/*	 * Edge triggered interrupts need to remember	 * pending events.	 * This applies to any hw interrupts that allow a second	 * instance of the same irq to arrive while we are in do_IRQ	 * or in the handler. But the code here only handles the _second_	 * instance of the irq, not the third or fourth. So it is mostly	 * useful for irq hardware that does not mask cleanly in an	 * SMP environment.	 */	for (;;) {		spin_unlock(&desc->lock);		handle_irq_event(irq, regs, action);		spin_lock(&desc->lock);		if (likely(!(desc->status & IRQ_PENDING)))			break;		desc->status &= ~IRQ_PENDING;	}out:	desc->status &= ~IRQ_INPROGRESS;	/*	 * The ->end() handler has to deal with interrupts which got	 * disabled while the handler was running.	 */	if (irq_desc[irq].handler) {		if (irq_desc[irq].handler->end)			irq_desc[irq].handler->end(irq);		else if (irq_desc[irq].handler->enable)			irq_desc[irq].handler->enable(irq);	}	spin_unlock(&desc->lock);}void do_IRQ(struct pt_regs *regs){	int irq, first = 1;        irq_enter();	/*	 * Every platform is required to implement ppc_md.get_irq.	 * This function will either return an irq number or -1 to	 * indicate there are no more pending.  But the first time	 * through the loop this means there wasn't and IRQ pending.	 * The value -2 is for buggy hardware and means that this IRQ	 * has already been handled. -- Tom	 */	while ((irq = ppc_md.get_irq(regs)) >= 0) {		ppc_irq_dispatch_handler(regs, irq);		first = 0;	}	if (irq != -2 && first)		/* That's not SMP safe ... but who cares ? */		ppc_spurious_interrupts++;        irq_exit();}unsigned long probe_irq_on (void){	return 0;}EXPORT_SYMBOL(probe_irq_on);int probe_irq_off (unsigned long irqs){	return 0;}EXPORT_SYMBOL(probe_irq_off);unsigned int probe_irq_mask(unsigned long irqs){	return 0;}#ifdef CONFIG_SMPvoid synchronize_irq(unsigned int irq){	while (irq_desc[irq].status & IRQ_INPROGRESS)		barrier();}#endif /* CONFIG_SMP */static struct proc_dir_entry *root_irq_dir;static struct proc_dir_entry *irq_dir[NR_IRQS];static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];#ifdef CONFIG_IRQ_ALL_CPUS#define DEFAULT_CPU_AFFINITY CPU_MASK_ALL#else#define DEFAULT_CPU_AFFINITY cpumask_of_cpu(0)#endifcpumask_t irq_affinity [NR_IRQS];static int irq_affinity_read_proc (char *page, char **start, off_t off,			int count, int *eof, void *data){	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);	if (count - len < 2)		return -EINVAL;	len += sprintf(page + len, "\n");	return len;}static int irq_affinity_write_proc (struct file *file, const char __user *buffer,					unsigned long count, void *data){	int irq = (int) data, full_count = count, err;	cpumask_t new_value, tmp;	if (!irq_desc[irq].handler->set_affinity)		return -EIO;	err = cpumask_parse(buffer, count, new_value);	/*	 * Do not allow disabling IRQs completely - it's a too easy	 * way to make the system unusable accidentally :-) At least	 * one online CPU still has to be targeted.	 *	 * We assume a 1-1 logical<->physical cpu mapping here.  If	 * we assume that the cpu indices in /proc/irq/../smp_affinity	 * are actually logical cpu #'s then we have no problem.	 *  -- Cort <cort@fsmlabs.com>	 */	cpus_and(tmp, new_value, cpu_online_map);	if (cpus_empty(tmp))		return -EINVAL;	irq_affinity[irq] = new_value;	irq_desc[irq].handler->set_affinity(irq, new_value);	return full_count;}static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,			int count, int *eof, void *data){	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);	if (count - len < 2)		return -EINVAL;	len += sprintf(page + len, "\n");	return len;}static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,					unsigned long count, void *data){	int err;	int full_count = count;	cpumask_t *mask = (cpumask_t *)data;	cpumask_t new_value;	err = cpumask_parse(buffer, count, new_value);	if (err)		return err;	*mask = new_value;	return full_count;}#define MAX_NAMELEN 10static void register_irq_proc (unsigned int irq){	struct proc_dir_entry *entry;	char name [MAX_NAMELEN];	if (!root_irq_dir || (irq_desc[irq].handler == NULL) || irq_dir[irq])		return;	memset(name, 0, MAX_NAMELEN);	sprintf(name, "%d", irq);	/* create /proc/irq/1234 */	irq_dir[irq] = proc_mkdir(name, root_irq_dir);	/* create /proc/irq/1234/smp_affinity */	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);	entry->nlink = 1;	entry->data = (void *)irq;	entry->read_proc = irq_affinity_read_proc;	entry->write_proc = irq_affinity_write_proc;	smp_affinity_entry[irq] = entry;}unsigned long prof_cpu_mask = -1;void init_irq_proc (void){	struct proc_dir_entry *entry;	int i;	/* create /proc/irq */	root_irq_dir = proc_mkdir("irq", NULL);	/* create /proc/irq/prof_cpu_mask */	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);	entry->nlink = 1;	entry->data = (void *)&prof_cpu_mask;	entry->read_proc = prof_cpu_mask_read_proc;	entry->write_proc = prof_cpu_mask_write_proc;	/*	 * Create entries for all existing IRQs.	 */	for (i = 0; i < NR_IRQS; i++) {		if (irq_desc[i].handler == NULL)			continue;		register_irq_proc(i);	}}irqreturn_t no_action(int irq, void *dev, struct pt_regs *regs){	return IRQ_NONE;}void __init init_IRQ(void){	int i;	for (i = 0; i < NR_IRQS; ++i)		irq_affinity[i] = DEFAULT_CPU_AFFINITY;	ppc_md.init_IRQ();}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?