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

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

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-riscv-imsic-platform.c
Extension
.c
Size
10771 bytes
Lines
391
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

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2021 Western Digital Corporation or its affiliates.
 * Copyright (C) 2022 Ventana Micro Systems Inc.
 */

#define pr_fmt(fmt) "riscv-imsic: " fmt
#include <linux/acpi.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/smp.h>

#include <linux/irqchip/irq-msi-lib.h>
#include "irq-riscv-imsic-state.h"

static bool imsic_cpu_page_phys(unsigned int cpu, unsigned int guest_index,
				phys_addr_t *out_msi_pa)
{
	struct imsic_global_config *global;
	struct imsic_local_config *local;

	global = &imsic->global;
	local = per_cpu_ptr(global->local, cpu);

	if (BIT(global->guest_index_bits) <= guest_index)
		return false;

	if (out_msi_pa)
		*out_msi_pa = local->msi_pa + (guest_index * IMSIC_MMIO_PAGE_SZ);

	return true;
}

static void imsic_irq_mask(struct irq_data *d)
{
	imsic_vector_mask(irq_data_get_irq_chip_data(d));
}

static void imsic_irq_unmask(struct irq_data *d)
{
	imsic_vector_unmask(irq_data_get_irq_chip_data(d));
}

static int imsic_irq_retrigger(struct irq_data *d)
{
	struct imsic_vector *vec = irq_data_get_irq_chip_data(d);
	struct imsic_local_config *local;

	if (WARN_ON(!vec))
		return -ENOENT;

	local = per_cpu_ptr(imsic->global.local, vec->cpu);
	writel_relaxed(vec->local_id, local->msi_va);
	return 0;
}

static void imsic_irq_ack(struct irq_data *d)
{
	irq_move_irq(d);
}

static void imsic_irq_compose_vector_msg(struct imsic_vector *vec, struct msi_msg *msg)
{
	phys_addr_t msi_addr;

	if (WARN_ON(!vec))
		return;

	if (WARN_ON(!imsic_cpu_page_phys(vec->cpu, 0, &msi_addr)))
		return;

	msg->address_hi = upper_32_bits(msi_addr);
	msg->address_lo = lower_32_bits(msi_addr);
	msg->data = vec->local_id;
}

static void imsic_irq_compose_msg(struct irq_data *d, struct msi_msg *msg)
{
	imsic_irq_compose_vector_msg(irq_data_get_irq_chip_data(d), msg);
}

Annotation

Implementation Notes