void do_interrupt()

in kernel/traps.c [260:307]


void do_interrupt(struct pt_regs *regs)
{
	static const unsigned int_level_mask[] = {
		0,
		XCHAL_INTLEVEL1_MASK,
		XCHAL_INTLEVEL2_MASK,
		XCHAL_INTLEVEL3_MASK,
		XCHAL_INTLEVEL4_MASK,
		XCHAL_INTLEVEL5_MASK,
		XCHAL_INTLEVEL6_MASK,
		XCHAL_INTLEVEL7_MASK,
	};
	struct pt_regs *old_regs;
	unsigned unhandled = ~0u;

	trace_hardirqs_off();

	old_regs = set_irq_regs(regs);
	irq_enter();

	for (;;) {
		unsigned intread = xtensa_get_sr(interrupt);
		unsigned intenable = xtensa_get_sr(intenable);
		unsigned int_at_level = intread & intenable;
		unsigned level;

		for (level = LOCKLEVEL; level > 0; --level) {
			if (int_at_level & int_level_mask[level]) {
				int_at_level &= int_level_mask[level];
				if (int_at_level & unhandled)
					int_at_level &= unhandled;
				else
					unhandled |= int_level_mask[level];
				break;
			}
		}

		if (level == 0)
			break;

		/* clear lowest pending irq in the unhandled mask */
		unhandled ^= (int_at_level & -int_at_level);
		do_IRQ(__ffs(int_at_level), regs);
	}

	irq_exit();
	set_irq_regs(old_regs);
}