drivers/irqchip/irq-econet-en751221.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-econet-en751221.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-econet-en751221.c
Extension
.c
Size
13552 bytes
Lines
481
Domain
Driver Families
Bucket
drivers/irqchip
Inferred role
Driver Families: implementation source
Status
source 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

if (shadow > IRQ_COUNT) {
			pr_err("%pOF: %s[%d] shadow(%d) out of range\n",
			       node, field, i + 1, shadow);
			continue;
		}

		if (target >= IRQ_COUNT) {
			pr_err("%pOF: %s[%d] target(%d) out of range\n", node, field, i, target);
			continue;
		}

		if (econet_intc.interrupt_shadows[target] != NOT_PERCPU) {
			pr_err("%pOF: %s[%d] target(%d) already has a shadow\n",
			       node, field, i, target);
			continue;
		}

		if (econet_intc.interrupt_shadows[shadow] != NOT_PERCPU) {
			pr_err("%pOF: %s[%d] shadow(%d) already has a target\n",
			       node, field, i + 1, shadow);
			continue;
		}

		econet_intc.interrupt_shadows[target] = shadow;
		econet_intc.interrupt_shadows[shadow] = IS_SHADOW;
	}

	return 0;
}

/**
 * econet_cpu_init() - configure routing of CPU interrupts to the correct domain.
 * @node: The devicetree node of this interrupt controller.
 *
 * Interrupts that originate from the CPU are unconditionally unmasked here and are re-routed back
 * to the IPI irq_domain in the CPU intc. Masking still takes place but the CPU intc is in charge
 * of it, using the mask bits of the c0_status register.
 *
 * Note that because IP2 ... IP7 are repurposed as Interrupt Priority Level, only the two IPI
 * interrupts are actually supported.
 */
static int __init econet_cpu_init(struct device_node *node)
{
	const char *field = "econet,cpu-interrupt-map";
	struct device_node *parent_intc;
	int map_size;
	u32 mask;

	map_size = of_property_count_u32_elems(node, field);

	if (map_size <= 0) {
		return 0;
	} else if (map_size % 2) {
		pr_err("%pOF: %s count is odd, ignoring\n", node, field);
		return 0;
	}

	u32 *maps __free(kfree) = kmalloc_array(map_size, sizeof(u32), GFP_KERNEL);
	if (!maps)
		return -ENOMEM;

	if (of_property_read_u32_array(node, field, maps, map_size)) {
		pr_err("%pOF: Failed to read %s\n", node, field);
		return -EINVAL;
	}

	/* Validation */
	for (int i = 0; i < map_size; i += 2) {
		u32 receive = maps[i];
		u32 dispatch = maps[i + 1];
		u8 shadow;

		if (receive >= IRQ_COUNT) {
			pr_err("%pOF: Entry %d:%d in %s (%u) is out of bounds\n",
			       node, i, 0, field, receive);
			return -EINVAL;
		}

		shadow = econet_intc.interrupt_shadows[receive];
		if (shadow != NOT_PERCPU && shadow >= IRQ_COUNT) {
			pr_err("%pOF: Entry %d:%d in %s (%u) has invalid shadow (%d)\n",
			       node, i, 0, field, receive, shadow);
			return -EINVAL;
		}

		if (dispatch >= ARRAY_SIZE(econet_cpu_dispatchers)) {
			pr_err("%pOF: Entry %d:%d in %s (%u) is out of bounds only IPI interrupts are supported\n",
			       node, i, 1, field, dispatch);
			return -EINVAL;
		}

Annotation

Implementation Notes