drivers/acpi/riscv/irq.c

Source file repositories/reference/linux-study-clean/drivers/acpi/riscv/irq.c

File Facts

System
Linux kernel
Corpus path
drivers/acpi/riscv/irq.c
Extension
.c
Size
10935 bytes
Lines
407
Domain
Driver Families
Bucket
drivers/acpi
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

struct riscv_ext_intc_list {
	acpi_handle		handle;
	u32			gsi_base;
	u32			nr_irqs;
	u32			nr_idcs;
	u32			id;
	u32			type;
	u32			flag;
	struct list_head	list;
};

struct acpi_irq_dep_ctx {
	int		rc;
	unsigned int	index;
	acpi_handle	handle;
};

LIST_HEAD(ext_intc_list);

static int irqchip_cmp_func(const void *in0, const void *in1)
{
	struct acpi_probe_entry *elem0 = (struct acpi_probe_entry *)in0;
	struct acpi_probe_entry *elem1 = (struct acpi_probe_entry *)in1;

	return (elem0->type > elem1->type) - (elem0->type < elem1->type);
}

/*
 * On RISC-V, RINTC structures in MADT should be probed before any other
 * interrupt controller structures and IMSIC before APLIC. The interrupt
 * controller subtypes in MADT of ACPI spec for RISC-V are defined in
 * the incremental order like RINTC(24)->IMSIC(25)->APLIC(26)->PLIC(27).
 * Hence, simply sorting the subtypes in incremental order will
 * establish the required order.
 */
void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr)
{
	struct acpi_probe_entry *ape = ap_head;

	if (nr == 1 || !ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id))
		return;
	sort(ape, nr, sizeof(*ape), irqchip_cmp_func, NULL);
}

static acpi_status riscv_acpi_update_gsi_handle(u32 gsi_base, acpi_handle handle)
{
	struct riscv_ext_intc_list *ext_intc_element;
	struct list_head *i, *tmp;

	list_for_each_safe(i, tmp, &ext_intc_list) {
		ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
		if (gsi_base == ext_intc_element->gsi_base) {
			ext_intc_element->handle = handle;
			return AE_OK;
		}
	}

	return AE_NOT_FOUND;
}

int riscv_acpi_update_gsi_range(u32 gsi_base, u32 nr_irqs)
{
	struct riscv_ext_intc_list *ext_intc_element;

	list_for_each_entry(ext_intc_element, &ext_intc_list, list) {
		if (gsi_base == ext_intc_element->gsi_base &&
		    (ext_intc_element->flag & RISCV_ACPI_INTC_FLAG_PENDING)) {
			ext_intc_element->nr_irqs = nr_irqs;
			ext_intc_element->flag &= ~RISCV_ACPI_INTC_FLAG_PENDING;
			return 0;
		}
	}

	return -ENODEV;
}

int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base,
			    u32 *id, u32 *nr_irqs, u32 *nr_idcs)
{
	struct riscv_ext_intc_list *ext_intc_element;
	struct list_head *i;

	list_for_each(i, &ext_intc_list) {
		ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
		if (ext_intc_element->handle == ACPI_HANDLE_FWNODE(fwnode)) {
			*gsi_base = ext_intc_element->gsi_base;
			*id = ext_intc_element->id;
			*nr_irqs = ext_intc_element->nr_irqs;
			if (nr_idcs)
				*nr_idcs = ext_intc_element->nr_idcs;

Annotation

Implementation Notes