arch/powerpc/kernel/irq_64.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kernel/irq_64.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kernel/irq_64.c
Extension
.c
Size
14382 bytes
Lines
523
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

irq_happened_test_and_clear(PACA_IRQ_HMI)) {
		regs.trap = INTERRUPT_HMI;
		handle_hmi_exception(&regs);
		next_interrupt(&regs);
	}

	if (irq_happened_test_and_clear(PACA_IRQ_DEC)) {
		regs.trap = INTERRUPT_DECREMENTER;
		timer_interrupt(&regs);
		next_interrupt(&regs);
	}

	if (irq_happened_test_and_clear(PACA_IRQ_EE)) {
		regs.trap = INTERRUPT_EXTERNAL;
		do_IRQ(&regs);
		next_interrupt(&regs);
	}

	if (IS_ENABLED(CONFIG_PPC_DOORBELL) &&
	    irq_happened_test_and_clear(PACA_IRQ_DBELL)) {
		regs.trap = INTERRUPT_DOORBELL;
		doorbell_exception(&regs);
		next_interrupt(&regs);
	}

	/* Book3E does not support soft-masking PMI interrupts */
	if (IS_ENABLED(CONFIG_PPC_BOOK3S) &&
	    irq_happened_test_and_clear(PACA_IRQ_PMI)) {
		regs.trap = INTERRUPT_PERFMON;
		performance_monitor_exception(&regs);
		next_interrupt(&regs);
	}

	local_paca->irq_happened &= ~PACA_IRQ_REPLAYING;
}

__no_kcsan void replay_soft_interrupts(void)
{
	irq_enter(); /* See comment in arch_local_irq_restore */
	__replay_soft_interrupts();
	irq_exit();
}

#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_KUAP)
static inline __no_kcsan void replay_soft_interrupts_irqrestore(void)
{
	unsigned long kuap_state = get_kuap();

	/*
	 * Check if anything calls local_irq_enable/restore() when KUAP is
	 * disabled (user access enabled). We handle that case here by saving
	 * and re-locking AMR but we shouldn't get here in the first place,
	 * hence the warning.
	 */
	kuap_assert_locked();

	if (kuap_state != AMR_KUAP_BLOCKED)
		set_kuap(AMR_KUAP_BLOCKED);

	__replay_soft_interrupts();

	if (kuap_state != AMR_KUAP_BLOCKED)
		set_kuap(kuap_state);
}
#else
#define replay_soft_interrupts_irqrestore() __replay_soft_interrupts()
#endif

notrace __no_kcsan void arch_local_irq_restore(unsigned long mask)
{
	unsigned char irq_happened;

	/* Write the new soft-enabled value if it is a disable */
	if (mask) {
		irq_soft_mask_set(mask);
		return;
	}

	if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
		WARN_ON_ONCE(in_nmi());
		WARN_ON_ONCE(in_hardirq());
		WARN_ON_ONCE(local_paca->irq_happened & PACA_IRQ_REPLAYING);
	}

again:
	/*
	 * After the stb, interrupts are unmasked and there are no interrupts
	 * pending replay. The restart sequence makes this atomic with
	 * respect to soft-masked interrupts. If this was just a simple code
	 * sequence, a soft-masked interrupt could become pending right after

Annotation

Implementation Notes