diff options
Diffstat (limited to 'arch/m68k/kernel/ints.c')
| -rw-r--r-- | arch/m68k/kernel/ints.c | 171 | 
1 files changed, 123 insertions, 48 deletions
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 3ce7c6166bb..c7f6ee67fd5 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -45,7 +45,15 @@  #endif  /* table for system interrupt handlers */ -static irq_handler_t irq_list[SYS_IRQS]; +static struct irq_node *irq_list[SYS_IRQS]; +static struct irq_controller *irq_controller[SYS_IRQS]; + +static struct irq_controller auto_irq_controller = { +	.name		= "auto", +	.lock		= SPIN_LOCK_UNLOCKED, +	.startup	= m68k_irq_startup, +	.shutdown	= m68k_irq_shutdown, +};  static const char *default_names[SYS_IRQS] = {  	[0] = "spurious int", @@ -101,17 +109,13 @@ void __init init_IRQ(void)  		hardirq_mask_is_broken();  	} -	for (i = 0; i < SYS_IRQS; i++) { -		if (mach_default_handler) -			irq_list[i].handler = (*mach_default_handler)[i]; -		irq_list[i].flags   = 0; -		irq_list[i].dev_id  = NULL; -		irq_list[i].devname = default_names[i]; +	for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) { +		irq_controller[i] = &auto_irq_controller; +		if (mach_default_handler && (*mach_default_handler)[i]) +			cpu_request_irq(i, (*mach_default_handler)[i], +					0, default_names[i], NULL);  	} -	for (i = 0; i < NUM_IRQ_NODES; i++) -		nodes[i].handler = NULL; -  	mach_init_IRQ ();  } @@ -120,9 +124,12 @@ irq_node_t *new_irq_node(void)  	irq_node_t *node;  	short i; -	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) -		if (!node->handler) +	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) { +		if (!node->handler) { +			memset(node, 0, sizeof(*node));  			return node; +		} +	}  	printk ("new_irq_node: out of nodes\n");  	return NULL; @@ -149,55 +156,115 @@ void free_irq(unsigned int irq, void *dev_id)  EXPORT_SYMBOL(free_irq); -int cpu_request_irq(unsigned int irq, -                    irqreturn_t (*handler)(int, void *, struct pt_regs *), -                    unsigned long flags, const char *devname, void *dev_id) +int setup_irq(unsigned int irq, struct irq_node *node)  { -	if (irq < IRQ_AUTO_1 || irq > IRQ_AUTO_7) { +	struct irq_controller *contr; +	struct irq_node **prev; +	unsigned long flags; + +	if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) {  		printk("%s: Incorrect IRQ %d from %s\n", -		       __FUNCTION__, irq, devname); +		       __FUNCTION__, irq, node->devname);  		return -ENXIO;  	} -#if 0 -	if (!(irq_list[irq].flags & IRQ_FLG_STD)) { -		if (irq_list[irq].flags & IRQ_FLG_LOCK) { -			printk("%s: IRQ %d from %s is not replaceable\n", -			       __FUNCTION__, irq, irq_list[irq].devname); -			return -EBUSY; -		} -		if (!(flags & IRQ_FLG_REPLACE)) { -			printk("%s: %s can't replace IRQ %d from %s\n", -			       __FUNCTION__, devname, irq, irq_list[irq].devname); +	spin_lock_irqsave(&contr->lock, flags); + +	prev = irq_list + irq; +	if (*prev) { +		/* Can't share interrupts unless both agree to */ +		if (!((*prev)->flags & node->flags & SA_SHIRQ)) { +			spin_unlock_irqrestore(&contr->lock, flags);  			return -EBUSY;  		} +		while (*prev) +			prev = &(*prev)->next;  	} -#endif -	irq_list[irq].handler = handler; -	irq_list[irq].flags   = flags; -	irq_list[irq].dev_id  = dev_id; -	irq_list[irq].devname = devname; +	if (!irq_list[irq]) { +		if (contr->startup) +			contr->startup(irq); +		else +			contr->enable(irq); +	} +	node->next = NULL; +	*prev = node; + +	spin_unlock_irqrestore(&contr->lock, flags); +  	return 0;  } +int cpu_request_irq(unsigned int irq, +                    irqreturn_t (*handler)(int, void *, struct pt_regs *), +                    unsigned long flags, const char *devname, void *dev_id) +{ +	struct irq_node *node; +	int res; + +	node = new_irq_node(); +	if (!node) +		return -ENOMEM; + +	node->handler = handler; +	node->flags   = flags; +	node->dev_id  = dev_id; +	node->devname = devname; + +	res = setup_irq(irq, node); +	if (res) +		node->handler = NULL; + +	return res; +} +  void cpu_free_irq(unsigned int irq, void *dev_id)  { -	if (irq < IRQ_AUTO_1 || irq > IRQ_AUTO_7) { +	struct irq_controller *contr; +	struct irq_node **p, *node; +	unsigned long flags; + +	if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) {  		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);  		return;  	} -	if (irq_list[irq].dev_id != dev_id) -		printk("%s: Removing probably wrong IRQ %d from %s\n", -		       __FUNCTION__, irq, irq_list[irq].devname); +	spin_lock_irqsave(&contr->lock, flags); + +	p = irq_list + irq; +	while ((node = *p)) { +		if (node->dev_id == dev_id) +			break; +		p = &node->next; +	} + +	if (node) { +		*p = node->next; +		node->handler = NULL; +	} else +		printk("%s: Removing probably wrong IRQ %d\n", +		       __FUNCTION__, irq); + +	if (!irq_list[irq]) +		contr->shutdown(irq); -	irq_list[irq].handler = (*mach_default_handler)[irq]; -	irq_list[irq].flags   = 0; -	irq_list[irq].dev_id  = NULL; -	irq_list[irq].devname = default_names[irq]; +	spin_unlock_irqrestore(&contr->lock, flags);  } +int m68k_irq_startup(unsigned int irq) +{ +	if (irq <= IRQ_AUTO_7) +		vectors[VEC_SPUR + irq] = auto_inthandler; +	return 0; +} + +void m68k_irq_shutdown(unsigned int irq) +{ +	if (irq <= IRQ_AUTO_7) +		vectors[VEC_SPUR + irq] = bad_inthandler; +} + +  /*   * Do we need these probe functions on the m68k?   * @@ -250,8 +317,14 @@ static void dummy_free_irq(unsigned int irq, void *dev_id)  asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs)  { +	struct irq_node *node; +  	kstat_cpu(0).irqs[irq]++; -	irq_list[irq].handler(irq, irq_list[irq].dev_id, regs); +	node = irq_list[irq]; +	do { +		node->handler(irq, node->dev_id, regs); +		node = node->next; +	} while (node);  }  asmlinkage void handle_badint(struct pt_regs *regs) @@ -262,16 +335,18 @@ asmlinkage void handle_badint(struct pt_regs *regs)  int show_interrupts(struct seq_file *p, void *v)  { +	struct irq_controller *contr; +	struct irq_node *node;  	int i = *(loff_t *) v;  	/* autovector interrupts */ -	if (i < SYS_IRQS) { -		if (mach_default_handler) { -			seq_printf(p, "auto %2d: %10u ", i, -			               i ? kstat_cpu(0).irqs[i] : num_spurious); -			seq_puts(p, "  "); -			seq_printf(p, "%s\n", irq_list[i].devname); -		} +	if (i < SYS_IRQS && irq_list[i]) { +		contr = irq_controller[i]; +		node = irq_list[i]; +		seq_printf(p, "%s %u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); +		while ((node = node->next)) +			seq_printf(p, ", %s", node->devname); +		seq_puts(p, "\n");  	} else if (i == SYS_IRQS)  		mach_get_irq_list(p, v);  	return 0;  |