irq.c
来自「linux 内核源代码」· C语言 代码 · 共 675 行 · 第 1/2 页
C
675 行
/* $Id: irq.c,v 1.114 2001/12/11 04:55:51 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQs are basically 'cast in stone' * and you are supposed to probe the prom's device * node trees to find out who's got which IRQ. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1995,2002 Pete A. Zaitcev (zaitcev@yahoo.com) * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) * Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org) */#include <linux/module.h>#include <linux/sched.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/linkage.h>#include <linux/kernel_stat.h>#include <linux/signal.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/random.h>#include <linux/init.h>#include <linux/smp.h>#include <linux/delay.h>#include <linux/threads.h>#include <linux/spinlock.h>#include <linux/seq_file.h>#include <asm/ptrace.h>#include <asm/processor.h>#include <asm/system.h>#include <asm/psr.h>#include <asm/smp.h>#include <asm/vaddrs.h>#include <asm/timer.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/traps.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/pgalloc.h>#include <asm/pgtable.h>#include <asm/pcic.h>#include <asm/cacheflush.h>#include <asm/irq_regs.h>#include "irq.h"#ifdef CONFIG_SMP#define SMP_NOP2 "nop; nop;\n\t"#define SMP_NOP3 "nop; nop; nop;\n\t"#else#define SMP_NOP2#define SMP_NOP3#endif /* SMP */unsigned long __raw_local_irq_save(void){ unsigned long retval; unsigned long tmp; __asm__ __volatile__( "rd %%psr, %0\n\t" SMP_NOP3 /* Sun4m + Cypress + SMP bug */ "or %0, %2, %1\n\t" "wr %1, 0, %%psr\n\t" "nop; nop; nop\n" : "=&r" (retval), "=r" (tmp) : "i" (PSR_PIL) : "memory"); return retval;}void raw_local_irq_enable(void){ unsigned long tmp; __asm__ __volatile__( "rd %%psr, %0\n\t" SMP_NOP3 /* Sun4m + Cypress + SMP bug */ "andn %0, %1, %0\n\t" "wr %0, 0, %%psr\n\t" "nop; nop; nop\n" : "=&r" (tmp) : "i" (PSR_PIL) : "memory");}void raw_local_irq_restore(unsigned long old_psr){ unsigned long tmp; __asm__ __volatile__( "rd %%psr, %0\n\t" "and %2, %1, %2\n\t" SMP_NOP2 /* Sun4m + Cypress + SMP bug */ "andn %0, %1, %0\n\t" "wr %0, %2, %%psr\n\t" "nop; nop; nop\n" : "=&r" (tmp) : "i" (PSR_PIL), "r" (old_psr) : "memory");}EXPORT_SYMBOL(__raw_local_irq_save);EXPORT_SYMBOL(raw_local_irq_enable);EXPORT_SYMBOL(raw_local_irq_restore);/* * Dave Redman (djhr@tadpole.co.uk) * * IRQ numbers.. These are no longer restricted to 15.. * * this is done to enable SBUS cards and onboard IO to be masked * correctly. using the interrupt level isn't good enough. * * For example: * A device interrupting at sbus level6 and the Floppy both come in * at IRQ11, but enabling and disabling them requires writing to * different bits in the SLAVIO/SEC. * * As a result of these changes sun4m machines could now support * directed CPU interrupts using the existing enable/disable irq code * with tweaks. * */static void irq_panic(void){ extern char *cputypval; prom_printf("machine: %s doesn't have irq handlers defined!\n",cputypval); prom_halt();}void (*sparc_init_timers)(irq_handler_t ) = (void (*)(irq_handler_t )) irq_panic;/* * Dave Redman (djhr@tadpole.co.uk) * * There used to be extern calls and hard coded values here.. very sucky! * instead, because some of the devices attach very early, I do something * equally sucky but at least we'll never try to free statically allocated * space or call kmalloc before kmalloc_init :(. * * In fact it's the timer10 that attaches first.. then timer14 * then kmalloc_init is called.. then the tty interrupts attach. * hmmm.... * */#define MAX_STATIC_ALLOC 4struct irqaction static_irqaction[MAX_STATIC_ALLOC];int static_irq_count;struct { struct irqaction *action; int flags;} sparc_irq[NR_IRQS];#define SPARC_IRQ_INPROGRESS 1/* Used to protect the IRQ action lists */DEFINE_SPINLOCK(irq_action_lock);int show_interrupts(struct seq_file *p, void *v){ int i = *(loff_t *) v; struct irqaction * action; unsigned long flags;#ifdef CONFIG_SMP int j;#endif if (sparc_cpu_model == sun4d) { extern int show_sun4d_interrupts(struct seq_file *, void *); return show_sun4d_interrupts(p, v); } spin_lock_irqsave(&irq_action_lock, flags); if (i < NR_IRQS) { action = sparc_irq[i].action; if (!action) goto out_unlock; seq_printf(p, "%3d: ", i);#ifndef CONFIG_SMP seq_printf(p, "%10u ", kstat_irqs(i));#else for_each_online_cpu(j) { seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); }#endif seq_printf(p, " %c %s", (action->flags & IRQF_DISABLED) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { seq_printf(p, ",%s %s", (action->flags & IRQF_DISABLED) ? " +" : "", action->name); } seq_putc(p, '\n'); }out_unlock: spin_unlock_irqrestore(&irq_action_lock, flags); return 0;}void free_irq(unsigned int irq, void *dev_id){ struct irqaction * action; struct irqaction **actionp; unsigned long flags; unsigned int cpu_irq; if (sparc_cpu_model == sun4d) { extern void sun4d_free_irq(unsigned int, void *); sun4d_free_irq(irq, dev_id); return; } cpu_irq = irq & (NR_IRQS - 1); if (cpu_irq > 14) { /* 14 irq levels on the sparc */ printk("Trying to free bogus IRQ %d\n", irq); return; } spin_lock_irqsave(&irq_action_lock, flags); actionp = &sparc_irq[cpu_irq].action; action = *actionp; if (!action->handler) { printk("Trying to free free IRQ%d\n",irq); goto out_unlock; } if (dev_id) { for (; action; action = action->next) { if (action->dev_id == dev_id) break; actionp = &action->next; } if (!action) { printk("Trying to free free shared IRQ%d\n",irq); goto out_unlock; } } else if (action->flags & IRQF_SHARED) { printk("Trying to free shared IRQ%d with NULL device ID\n", irq); goto out_unlock; } if (action->flags & SA_STATIC_ALLOC) { /* This interrupt is marked as specially allocated * so it is a bad idea to free it. */ printk("Attempt to free statically allocated IRQ%d (%s)\n", irq, action->name); goto out_unlock; } *actionp = action->next; spin_unlock_irqrestore(&irq_action_lock, flags); synchronize_irq(irq); spin_lock_irqsave(&irq_action_lock, flags); kfree(action); if (!sparc_irq[cpu_irq].action) __disable_irq(irq);out_unlock: spin_unlock_irqrestore(&irq_action_lock, flags);}EXPORT_SYMBOL(free_irq);/* * This is called when we want to synchronize with * interrupts. We may for example tell a device to * stop sending interrupts: but to make sure there * are no interrupts that are executing on another * CPU we need to call this function. */#ifdef CONFIG_SMPvoid synchronize_irq(unsigned int irq){ unsigned int cpu_irq; cpu_irq = irq & (NR_IRQS - 1); while (sparc_irq[cpu_irq].flags & SPARC_IRQ_INPROGRESS) cpu_relax();}#endif /* SMP */void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs){ int i; struct irqaction * action; unsigned int cpu_irq; cpu_irq = irq & (NR_IRQS - 1); action = sparc_irq[cpu_irq].action; printk("IO device interrupt, irq = %d\n", irq); printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, regs->npc, regs->u_regs[14]); if (action) { printk("Expecting: "); for (i = 0; i < 16; i++) if (action->handler) printk("[%s:%d:0x%x] ", action->name, (int) i, (unsigned int) action->handler); } printk("AIEEE\n"); panic("bogus interrupt received");}void handler_irq(int irq, struct pt_regs * regs){ struct pt_regs *old_regs; struct irqaction * action; int cpu = smp_processor_id();#ifdef CONFIG_SMP extern void smp4m_irq_rotate(int cpu);#endif old_regs = set_irq_regs(regs); irq_enter(); disable_pil_irq(irq);#ifdef CONFIG_SMP /* Only rotate on lower priority IRQs (scsi, ethernet, etc.). */ if((sparc_cpu_model==sun4m) && (irq < 10)) smp4m_irq_rotate(cpu);#endif action = sparc_irq[irq].action;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?