mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	irq: refactor and clean up the free_irq() code flow
Impact: cleanup - separate out the loop from the actual freeing logic, this wins us two indentation levels allowing a number of followup prettifications - turn the WARN_ON() into a more informative WARN(). - clean up the comments and the code flow some more Cc: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
		
							parent
							
								
									327ec5699c
								
							
						
					
					
						commit
						ae88a23b32
					
				
					 1 changed files with 58 additions and 51 deletions
				
			
		| 
						 | 
					@ -575,35 +575,49 @@ int setup_irq(unsigned int irq, struct irqaction *act)
 | 
				
			||||||
void free_irq(unsigned int irq, void *dev_id)
 | 
					void free_irq(unsigned int irq, void *dev_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct irq_desc *desc = irq_to_desc(irq);
 | 
						struct irq_desc *desc = irq_to_desc(irq);
 | 
				
			||||||
	struct irqaction **p;
 | 
						struct irqaction *action, **p, **pp;
 | 
				
			||||||
	unsigned long flags;
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WARN_ON(in_interrupt());
 | 
						WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!desc)
 | 
						if (!desc)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irqsave(&desc->lock, flags);
 | 
						spin_lock_irqsave(&desc->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * There can be multiple actions per IRQ descriptor, find the right
 | 
				
			||||||
 | 
						 * one based on the dev_id:
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	p = &desc->action;
 | 
						p = &desc->action;
 | 
				
			||||||
	for (;;) {
 | 
						for (;;) {
 | 
				
			||||||
		struct irqaction *action = *p;
 | 
							action = *p;
 | 
				
			||||||
 | 
							pp = p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (action) {
 | 
							if (!action) {
 | 
				
			||||||
			struct irqaction **pp = p;
 | 
								WARN(1, "Trying to free already-free IRQ %d\n", irq);
 | 
				
			||||||
 | 
								spin_unlock_irqrestore(&desc->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		p = &action->next;
 | 
							p = &action->next;
 | 
				
			||||||
		if (action->dev_id != dev_id)
 | 
							if (action->dev_id != dev_id)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Found it - now remove it from the list of entries */
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Found it - now remove it from the list of entries: */
 | 
				
			||||||
	*pp = action->next;
 | 
						*pp = action->next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Currently used only by UML, might disappear one day.*/
 | 
						/* Currently used only by UML, might disappear one day: */
 | 
				
			||||||
#ifdef CONFIG_IRQ_RELEASE_METHOD
 | 
					#ifdef CONFIG_IRQ_RELEASE_METHOD
 | 
				
			||||||
	if (desc->chip->release)
 | 
						if (desc->chip->release)
 | 
				
			||||||
		desc->chip->release(irq, dev_id);
 | 
							desc->chip->release(irq, dev_id);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If this was the last handler, shut down the IRQ line: */
 | 
				
			||||||
	if (!desc->action) {
 | 
						if (!desc->action) {
 | 
				
			||||||
		desc->status |= IRQ_DISABLED;
 | 
							desc->status |= IRQ_DISABLED;
 | 
				
			||||||
		if (desc->chip->shutdown)
 | 
							if (desc->chip->shutdown)
 | 
				
			||||||
| 
						 | 
					@ -612,18 +626,20 @@ void free_irq(unsigned int irq, void *dev_id)
 | 
				
			||||||
			desc->chip->disable(irq);
 | 
								desc->chip->disable(irq);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock_irqrestore(&desc->lock, flags);
 | 
						spin_unlock_irqrestore(&desc->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unregister_handler_proc(irq, action);
 | 
						unregister_handler_proc(irq, action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Make sure it's not being used on another CPU */
 | 
						/* Make sure it's not being used on another CPU: */
 | 
				
			||||||
	synchronize_irq(irq);
 | 
						synchronize_irq(irq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_DEBUG_SHIRQ
 | 
					#ifdef CONFIG_DEBUG_SHIRQ
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
			 * It's a shared IRQ -- the driver ought to be
 | 
						 * It's a shared IRQ -- the driver ought to be prepared for an IRQ
 | 
				
			||||||
			 * prepared for it to happen even now it's
 | 
						 * event to happen even now it's being freed, so let's make sure that
 | 
				
			||||||
			 * being freed, so let's make sure....  We do
 | 
						 * is so by doing an extra call to the handler ....
 | 
				
			||||||
			 * this after actually deregistering it, to
 | 
						 *
 | 
				
			||||||
			 * make sure that a 'real' IRQ doesn't run in
 | 
						 * ( We do this after actually deregistering it, to make sure that a
 | 
				
			||||||
			 * parallel with our fake
 | 
						 *   'real' IRQ doesn't run in * parallel with our fake. )
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (action->flags & IRQF_SHARED) {
 | 
						if (action->flags & IRQF_SHARED) {
 | 
				
			||||||
		local_irq_save(flags);
 | 
							local_irq_save(flags);
 | 
				
			||||||
| 
						 | 
					@ -632,15 +648,6 @@ void free_irq(unsigned int irq, void *dev_id)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	kfree(action);
 | 
						kfree(action);
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
 | 
					 | 
				
			||||||
#ifdef CONFIG_DEBUG_SHIRQ
 | 
					 | 
				
			||||||
		dump_stack();
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		spin_unlock_irqrestore(&desc->lock, flags);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(free_irq);
 | 
					EXPORT_SYMBOL(free_irq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue