drivers/irqchip/irq-riscv-imsic-early.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-riscv-imsic-early.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-riscv-imsic-early.c
Extension
.c
Size
7488 bytes
Lines
308
Domain
Driver Families
Bucket
drivers/irqchip
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static void imsic_ipi_starting_cpu(void) { }
static void imsic_ipi_dying_cpu(void) { }
static int __init imsic_ipi_domain_init(void) { return 0; }
#endif

/*
 * To handle an interrupt, we read the TOPEI CSR and write zero in one
 * instruction. If TOPEI CSR is non-zero then we translate TOPEI.ID to
 * Linux interrupt number and let Linux IRQ subsystem handle it.
 */
static void imsic_handle_irq(struct irq_desc *desc)
{
	struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv);
	struct irq_chip *chip = irq_desc_get_chip(desc);
	unsigned long local_id;

	/*
	 * Process pending local synchronization instead of waiting
	 * for per-CPU local timer to expire.
	 */
	imsic_local_sync_all(false);

	chained_irq_enter(chip, desc);

	while ((local_id = csr_swap(CSR_TOPEI, 0))) {
		local_id >>= TOPEI_ID_SHIFT;

		if (!imsic_noipi && local_id == IMSIC_IPI_ID) {
			if (IS_ENABLED(CONFIG_SMP))
				ipi_mux_process();
			continue;
		}

		if (unlikely(local_id > imsic->global.nr_ids)) {
			pr_warn_ratelimited("vector not found for local ID 0x%lx\n", local_id);
			continue;
		}

		generic_handle_irq(lpriv->vectors[local_id].irq);
	}

	chained_irq_exit(chip, desc);
}

static void imsic_hw_states_init(void)
{
	/* Setup IPIs */
	imsic_ipi_starting_cpu();

	/*
	 * Interrupts identities might have been enabled/disabled while
	 * this CPU was not running so sync-up local enable/disable state.
	 */
	imsic_local_sync_all(true);

	/* Enable local interrupt delivery */
	imsic_local_delivery(true);
}

static int imsic_starting_cpu(unsigned int cpu)
{
	/* Mark per-CPU IMSIC state as online */
	imsic_state_online();

	/* Enable per-CPU parent interrupt */
	enable_percpu_irq(imsic_parent_irq, irq_get_trigger_type(imsic_parent_irq));

	/* Initialize the IMSIC registers to enable the interrupt delivery */
	imsic_hw_states_init();

	return 0;
}

static int imsic_dying_cpu(unsigned int cpu)
{
	/* Cleanup IPIs */
	imsic_ipi_dying_cpu();

	imsic_local_sync_all(false);

	/* Mark per-CPU IMSIC state as offline */
	imsic_state_offline();

	return 0;
}

static int imsic_pm_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
	switch (cmd) {
	case CPU_PM_EXIT:

Annotation

Implementation Notes