mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	[PATCH] genirq: add genirq sw IRQ-retrigger
Enable platforms that do not have a hardware-assisted hardirq-resend mechanism to resend them via a softirq-driven IRQ emulation mechanism. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
		
							parent
							
								
									11c869eaf1
								
							
						
					
					
						commit
						a4633adcdb
					
				
					 4 changed files with 83 additions and 10 deletions
				
			
		|  | @ -246,6 +246,9 @@ extern void note_interrupt(unsigned int irq, struct irq_desc *desc, | |||
| 			   int action_ret, struct pt_regs *regs); | ||||
| extern int can_request_irq(unsigned int irq, unsigned long irqflags); | ||||
| 
 | ||||
| /* Resending of interrupts :*/ | ||||
| void check_irq_resend(struct irq_desc *desc, unsigned int irq); | ||||
| 
 | ||||
| extern void init_irq_proc(void); | ||||
| 
 | ||||
| #endif /* CONFIG_GENERIC_HARDIRQS */ | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| 
 | ||||
| obj-y := handle.o manage.o spurious.o | ||||
| obj-y := handle.o manage.o spurious.o resend.o | ||||
| obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o | ||||
| obj-$(CONFIG_PROC_FS) += proc.o | ||||
| obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o | ||||
|  |  | |||
|  | @ -118,15 +118,7 @@ void enable_irq(unsigned int irq) | |||
| 		WARN_ON(1); | ||||
| 		break; | ||||
| 	case 1: { | ||||
| 		unsigned int status = desc->status & ~IRQ_DISABLED; | ||||
| 
 | ||||
| 		desc->status = status; | ||||
| 		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { | ||||
| 			desc->status = status | IRQ_REPLAY; | ||||
| 			if (desc->chip && desc->chip->retrigger) | ||||
| 				desc->chip->retrigger(irq); | ||||
| 		} | ||||
| 		desc->chip->enable(irq); | ||||
| 		check_irq_resend(desc, irq); | ||||
| 		/* fall-through */ | ||||
| 	} | ||||
| 	default: | ||||
|  |  | |||
							
								
								
									
										78
									
								
								kernel/irq/resend.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								kernel/irq/resend.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,78 @@ | |||
| /*
 | ||||
|  * linux/kernel/irq/resend.c | ||||
|  * | ||||
|  * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar | ||||
|  * Copyright (C) 2005-2006, Thomas Gleixner | ||||
|  * | ||||
|  * This file contains the IRQ-resend code | ||||
|  * | ||||
|  * If the interrupt is waiting to be processed, we try to re-run it. | ||||
|  * We can't directly run it from here since the caller might be in an | ||||
|  * interrupt-protected region. Not all irq controller chips can | ||||
|  * retrigger interrupts at the hardware level, so in those cases | ||||
|  * we allow the resending of IRQs via a tasklet. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/irq.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/random.h> | ||||
| #include <linux/interrupt.h> | ||||
| 
 | ||||
| #include "internals.h" | ||||
| 
 | ||||
| #ifdef CONFIG_HARDIRQS_SW_RESEND | ||||
| 
 | ||||
| /* Bitmap to handle software resend of interrupts: */ | ||||
| static DECLARE_BITMAP(irqs_resend, NR_IRQS); | ||||
| 
 | ||||
| /*
 | ||||
|  * Run software resends of IRQ's | ||||
|  */ | ||||
| static void resend_irqs(unsigned long arg) | ||||
| { | ||||
| 	struct irq_desc *desc; | ||||
| 	int irq; | ||||
| 
 | ||||
| 	while (!bitmap_empty(irqs_resend, NR_IRQS)) { | ||||
| 		irq = find_first_bit(irqs_resend, NR_IRQS); | ||||
| 		clear_bit(irq, irqs_resend); | ||||
| 		desc = irq_desc + irq; | ||||
| 		spin_lock_irqsave(&desc->lock, flags); | ||||
| 		desc->handle_irq(irq, desc, NULL); | ||||
| 		spin_unlock_irqrestore(&desc->lock, flags); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Tasklet to handle resend: */ | ||||
| static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * IRQ resend | ||||
|  * | ||||
|  * Is called with interrupts disabled and desc->lock held. | ||||
|  */ | ||||
| void check_irq_resend(struct irq_desc *desc, unsigned int irq) | ||||
| { | ||||
| 	unsigned int status = desc->status; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Make sure the interrupt is enabled, before resending it: | ||||
| 	 */ | ||||
| 	desc->chip->enable(irq); | ||||
| 
 | ||||
| 	if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { | ||||
| 		desc->status &= ~IRQ_PENDING; | ||||
| 		desc->status = status | IRQ_REPLAY; | ||||
| 
 | ||||
| 		if (!desc->chip || !desc->chip->retrigger || | ||||
| 					!desc->chip->retrigger(irq)) { | ||||
| #ifdef CONFIG_HARDIRQS_SW_RESEND | ||||
| 			/* Set it pending and activate the softirq: */ | ||||
| 			set_bit(irq, irqs_resend); | ||||
| 			tasklet_schedule(&resend_tasklet); | ||||
| #endif | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in a new issue
	
	 Thomas Gleixner
						Thomas Gleixner