Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a304e1b8 authored by David Woodhouse's avatar David Woodhouse Committed by Linus Torvalds
Browse files

[PATCH] Debug shared irqs



Drivers registering IRQ handlers with SA_SHIRQ really ought to be able to
handle an interrupt happening before request_irq() returns.  They also
ought to be able to handle an interrupt happening during the start of their
call to free_irq().  Let's test that hypothesis....

[bunk@stusta.de: Kconfig fixes]
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
Cc: Arjan van de Ven <arjan@infradead.org>
Signed-off-by: default avatarJesper Juhl <jesper.juhl@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAdrian Bunk <bunk@stusta.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f9e4acf3
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -357,6 +357,7 @@ void free_irq(unsigned int irq, void *dev_id)
	struct irq_desc *desc;
	struct irqaction **p;
	unsigned long flags;
	irqreturn_t (*handler)(int, void *) = NULL;

	WARN_ON(in_interrupt());
	if (irq >= NR_IRQS)
@@ -396,6 +397,8 @@ void free_irq(unsigned int irq, void *dev_id)

			/* Make sure it's not being used on another CPU */
			synchronize_irq(irq);
			if (action->flags & IRQF_SHARED)
				handler = action->handler;
			kfree(action);
			return;
		}
@@ -403,6 +406,17 @@ void free_irq(unsigned int irq, void *dev_id)
		spin_unlock_irqrestore(&desc->lock, flags);
		return;
	}
#ifdef CONFIG_DEBUG_SHIRQ
	if (handler) {
		/*
		 * It's a shared IRQ -- the driver ought to be prepared for it
		 * to happen even now it's being freed, so let's make sure....
		 * We do this after actually deregistering it, to make sure that
		 * a 'real' IRQ doesn't run in parallel with our fake
		 */
		handler(irq, dev_id);
	}
#endif
}
EXPORT_SYMBOL(free_irq);

@@ -475,6 +489,25 @@ int request_irq(unsigned int irq, irq_handler_t handler,

	select_smp_affinity(irq);

#ifdef CONFIG_DEBUG_SHIRQ
	if (irqflags & IRQF_SHARED) {
		/*
		 * It's a shared IRQ -- the driver ought to be prepared for it
		 * to happen immediately, so let's make sure....
		 * We do this before actually registering it, to make sure that
		 * a 'real' IRQ doesn't run in parallel with our fake
		 */
		if (irqflags & IRQF_DISABLED) {
			unsigned long flags;

			local_irq_save(flags);
			handler(irq, dev_id);
			local_irq_restore(flags);
		} else
			handler(irq, dev_id);
	}
#endif

	retval = setup_irq(irq, action);
	if (retval)
		kfree(action);
+9 −0
Original line number Diff line number Diff line
@@ -77,6 +77,15 @@ config DEBUG_KERNEL
	  Say Y here if you are developing drivers or trying to debug and
	  identify kernel problems.

config DEBUG_SHIRQ
	bool "Debug shared IRQ handlers"
	depends on DEBUG_KERNEL && GENERIC_HARDIRQS
	help
	  Enable this to generate a spurious interrupt as soon as a shared
	  interrupt handler is registered, and just before one is deregistered.
	  Drivers ought to be able to handle interrupts coming in at those
	  points; some don't and need to be caught.

config LOG_BUF_SHIFT
	int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
	range 12 21