diff options
Diffstat (limited to 'arch/sparc/kernel/irq.c')
| -rw-r--r-- | arch/sparc/kernel/irq.c | 614 |
1 files changed, 0 insertions, 614 deletions
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c deleted file mode 100644 index 410b9a72aba..00000000000 --- a/arch/sparc/kernel/irq.c +++ /dev/null @@ -1,614 +0,0 @@ -/* $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 IRQ's 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/config.h> -#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/sched.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/smp_lock.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> - -#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 __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 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 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(__local_irq_save); -EXPORT_SYMBOL(local_irq_enable); -EXPORT_SYMBOL(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)(irqreturn_t (*)(int, void *,struct pt_regs *)) = - (void (*)(irqreturn_t (*)(int, void *,struct pt_regs *))) 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 4 -struct irqaction static_irqaction[MAX_STATIC_ALLOC]; -int static_irq_count; - -struct irqaction *irq_action[NR_IRQS] = { - [0 ... (NR_IRQS-1)] = NULL -}; - -/* 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 = *(i + irq_action); - if (!action) - goto out_unlock; - seq_printf(p, "%3d: ", i); -#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(cpu_logical_map(j)).irqs[i]); - } -#endif - seq_printf(p, " %c %s", - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - seq_printf(p, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - 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 * tmp = NULL; - 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); - - action = *(cpu_irq + irq_action); - - 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; - tmp = action; - } - if (!action) { - printk("Trying to free free shared IRQ%d\n",irq); - goto out_unlock; - } - } else if (action->flags & SA_SHIRQ) { - 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; - } - - if (action && tmp) - tmp->next = action->next; - else - *(cpu_irq + irq_action) = action->next; - - spin_unlock_irqrestore(&irq_action_lock, flags); - - synchronize_irq(irq); - - spin_lock_irqsave(&irq_action_lock, flags); - - kfree(action); - - if (!(*(cpu_irq + 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_SMP -void synchronize_irq(unsigned int irq) -{ - printk("synchronize_irq says: implement me!\n"); - BUG(); -} -#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 = *(cpu_irq + 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 irqaction * action; - int cpu = smp_processor_id(); -#ifdef CONFIG_SMP - extern void smp4m_irq_rotate(int cpu); -#endif - - irq_enter(); - disable_pil_irq(irq); -#ifdef CONFIG_SMP - /* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */ - if(irq < 10) - smp4m_irq_rotate(cpu); -#endif - action = *(irq + irq_action); - kstat_cpu(cpu).irqs[irq]++; - do { - if (!action || !action->handler) - unexpected_irq(irq, NULL, regs); - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - enable_pil_irq(irq); - irq_exit(); -} - -#ifdef CONFIG_BLK_DEV_FD -extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs); - -void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - - disable_pil_irq(irq); - irq_enter(); - kstat_cpu(cpu).irqs[irq]++; - floppy_interrupt(irq, dev_id, regs); - irq_exit(); - enable_pil_irq(irq); - // XXX Eek, it's totally changed with preempt_count() and such - // if (softirq_pending(cpu)) - // do_softirq(); -} -#endif - -/* Fast IRQ's on the Sparc can only have one routine attached to them, - * thus no sharing possible. - */ -int request_fast_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char *devname) -{ - struct irqaction *action; - unsigned long flags; - unsigned int cpu_irq; - int ret; -#ifdef CONFIG_SMP - struct tt_entry *trap_table; - extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3; -#endif - - cpu_irq = irq & (NR_IRQS - 1); - if(cpu_irq > 14) { - ret = -EINVAL; - goto out; - } - if(!handler) { - ret = -EINVAL; - goto out; - } - - spin_lock_irqsave(&irq_action_lock, flags); - - action = *(cpu_irq + irq_action); - if(action) { - if(action->flags & SA_SHIRQ) - panic("Trying to register fast irq when already shared.\n"); - if(irqflags & SA_SHIRQ) - panic("Trying to register fast irq as shared.\n"); - - /* Anyway, someone already owns it so cannot be made fast. */ - printk("request_fast_irq: Trying to register yet already owned.\n"); - ret = -EBUSY; - goto out_unlock; - } - - /* If this is flagged as statically allocated then we use our - * private struct which is never freed. - */ - if (irqflags & SA_STATIC_ALLOC) { - if (static_irq_count < MAX_STATIC_ALLOC) - action = &static_irqaction[static_irq_count++]; - else - printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", - irq, devname); - } - - if (action == NULL) - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), - GFP_ATOMIC); - - if (!action) { - ret = -ENOMEM; - goto out_unlock; - } - - /* Dork with trap table if we get this far. */ -#define INSTANTIATE(table) \ - table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_RD_PSR_L0; \ - table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = \ - SPARC_BRANCH((unsigned long) handler, \ - (unsigned long) &table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two);\ - table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_RD_WIM_L3; \ - table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP; - - INSTANTIATE(sparc_ttable) -#ifdef CONFIG_SMP - trap_table = &trapbase_cpu1; INSTANTIATE(trap_table) - trap_table = &trapbase_cpu2; INSTANTIATE(trap_table) - trap_table = &trapbase_cpu3; INSTANTIATE(trap_table) -#endif -#undef INSTANTIATE - /* - * XXX Correct thing whould be to flush only I- and D-cache lines - * which contain the handler in question. But as of time of the - * writing we have no CPU-neutral interface to fine-grained flushes. - */ - flush_cache_all(); - - action->handler = handler; - action->flags = irqflags; - cpus_clear(action->mask); - action->name = devname; - action->dev_id = NULL; - action->next = NULL; - - *(cpu_irq + irq_action) = action; - - enable_irq(irq); - - ret = 0; -out_unlock: - spin_unlock_irqrestore(&irq_action_lock, flags); -out: - return ret; -} - -int request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ - struct irqaction * action, *tmp = NULL; - unsigned long flags; - unsigned int cpu_irq; - int ret; - - if (sparc_cpu_model == sun4d) { - extern int sun4d_request_irq(unsigned int, - irqreturn_t (*)(int, void *, struct pt_regs *), - unsigned long, const char *, void *); - return sun4d_request_irq(irq, handler, irqflags, devname, dev_id); - } - cpu_irq = irq & (NR_IRQS - 1); - if(cpu_irq > 14) { - ret = -EINVAL; - goto out; - } - if (!handler) { - ret = -EINVAL; - goto out; - } - - spin_lock_irqsave(&irq_action_lock, flags); - - action = *(cpu_irq + irq_action); - if (action) { - if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) { - for (tmp = action; tmp->next; tmp = tmp->next); - } else { - ret = -EBUSY; - goto out_unlock; - } - if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) { - printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq); - ret = -EBUSY; - goto out_unlock; - } - action = NULL; /* Or else! */ - } - - /* If this is flagged as statically allocated then we use our - * private struct which is never freed. - */ - if (irqflags & SA_STATIC_ALLOC) { - if (static_irq_count < MAX_STATIC_ALLOC) - action = &static_irqaction[static_irq_count++]; - else - printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", irq, devname); - } - - if (action == NULL) - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), - GFP_ATOMIC); - - if (!action) { - ret = -ENOMEM; - goto out_unlock; - } - - action->handler = handler; - action->flags = irqflags; - cpus_clear(action->mask); - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - if (tmp) - tmp->next = action; - else - *(cpu_irq + irq_action) = action; - - enable_irq(irq); - - ret = 0; -out_unlock: - spin_unlock_irqrestore(&irq_action_lock, flags); -out: - return ret; -} - -EXPORT_SYMBOL(request_irq); - -/* We really don't need these at all on the Sparc. We only have - * stubs here because they are exported to modules. - */ -unsigned long probe_irq_on(void) -{ - return 0; -} - -EXPORT_SYMBOL(probe_irq_on); - -int probe_irq_off(unsigned long mask) -{ - return 0; -} - -EXPORT_SYMBOL(probe_irq_off); - -/* djhr - * This could probably be made indirect too and assigned in the CPU - * bits of the code. That would be much nicer I think and would also - * fit in with the idea of being able to tune your kernel for your machine - * by removing unrequired machine and device support. - * - */ - -void __init init_IRQ(void) -{ - extern void sun4c_init_IRQ( void ); - extern void sun4m_init_IRQ( void ); - extern void sun4d_init_IRQ( void ); - - switch(sparc_cpu_model) { - case sun4c: - case sun4: - sun4c_init_IRQ(); - break; - - case sun4m: -#ifdef CONFIG_PCI - pcic_probe(); - if (pcic_present()) { - sun4m_pci_init_IRQ(); - break; - } -#endif - sun4m_init_IRQ(); - break; - - case sun4d: - sun4d_init_IRQ(); - break; - - default: - prom_printf("Cannot initialize IRQ's on this Sun machine..."); - break; - } - btfixup(); -} - -void init_irq_proc(void) -{ - /* For now, nothing... */ -} |
