drivers/irqchip/irq-loongson-eiointc.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-loongson-eiointc.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-loongson-eiointc.c
Extension
.c
Size
17545 bytes
Lines
681
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

struct eiointc_ip_route {
	struct eiointc_priv	*priv;
	/* Offset Routed destination IP */
	int			start;
	int			end;
};

struct eiointc_priv {
	u32			node;
	u32			vec_count;
	nodemask_t		node_map;
	cpumask_t		cpuspan_map;
	struct fwnode_handle	*domain_handle;
	struct irq_domain	*eiointc_domain;
	int			flags;
	irq_hw_number_t		parent_hwirq;
	struct eiointc_ip_route	route_info[VEC_REG_COUNT];
};

static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];

static void eiointc_enable(void)
{
#ifdef CONFIG_MACH_LOONGSON64
	uint64_t misc;

	misc = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC);
	misc |= IOCSR_MISC_FUNC_EXT_IOI_EN;
	iocsr_write64(misc, LOONGARCH_IOCSR_MISC_FUNC);
#endif
}

static int cpu_to_eio_node(int cpu)
{
	if (!kvm_para_has_feature(KVM_FEATURE_VIRT_EXTIOI))
		return cpu_logical_map(cpu) / CORES_PER_EIO_NODE;
	else
		return cpu_logical_map(cpu) / CORES_PER_VEIO_NODE;
}

#ifdef CONFIG_SMP
static void eiointc_set_irq_route(int pos, unsigned int cpu, unsigned int mnode, nodemask_t *node_map)
{
	int i, node, cpu_node, route_node;
	unsigned char coremap;
	uint32_t pos_off, data, data_byte, data_mask;

	pos_off = pos & ~3;
	data_byte = pos & 3;
	data_mask = ~BIT_MASK(data_byte) & 0xf;

	/* Calculate node and coremap of target irq */
	cpu_node = cpu_logical_map(cpu) / CORES_PER_EIO_NODE;
	coremap = BIT(cpu_logical_map(cpu) % CORES_PER_EIO_NODE);

	for_each_online_cpu(i) {
		node = cpu_to_eio_node(i);
		if (!node_isset(node, *node_map))
			continue;

		/* EIO node 0 is in charge of inter-node interrupt dispatch */
		route_node = (node == mnode) ? cpu_node : node;
		data = ((coremap | (route_node << 4)) << (data_byte * 8));
		csr_any_send(EIOINTC_REG_ROUTE + pos_off, data, data_mask, node * CORES_PER_EIO_NODE);
	}
}

static void veiointc_set_irq_route(unsigned int vector, unsigned int cpu)
{
	unsigned long reg = EIOINTC_REG_ROUTE_VEC(vector);
	unsigned int data;

	data = iocsr_read32(reg);
	data &= ~EIOINTC_REG_ROUTE_VEC_MASK(vector);
	data |= cpu_logical_map(cpu) << EIOINTC_REG_ROUTE_VEC_SHIFT(vector);
	iocsr_write32(data, reg);
}

static DEFINE_RAW_SPINLOCK(affinity_lock);

static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, bool force)
{
	unsigned int cpu;
	unsigned long flags;
	uint32_t vector, regaddr;
	struct eiointc_priv *priv = d->domain->host_data;

	raw_spin_lock_irqsave(&affinity_lock, flags);

	cpu = cpumask_first_and_and(&priv->cpuspan_map, affinity, cpu_online_mask);

Annotation

Implementation Notes