arch/loongarch/kvm/intc/pch_pic.c

Source file repositories/reference/linux-study-clean/arch/loongarch/kvm/intc/pch_pic.c

File Facts

System
Linux kernel
Corpus path
arch/loongarch/kvm/intc/pch_pic.c
Extension
.c
Size
11816 bytes
Lines
503
Domain
Architecture Layer
Bucket
arch/loongarch
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (mask & s->irr & ~s->mask) {
			s->isr |= mask;
			irq = s->htmsi_vector[irq];
			eiointc_set_irq(s->kvm->arch.eiointc, irq, level);
		}
	} else {
		if (mask & s->isr & ~s->irr) {
			s->isr &= ~mask;
			irq = s->htmsi_vector[irq];
			eiointc_set_irq(s->kvm->arch.eiointc, irq, level);
		}
	}
}

/* update batch irqs, the irq_mask is a bitmap of irqs */
static void pch_pic_update_batch_irqs(struct loongarch_pch_pic *s, u64 irq_mask, int level)
{
	unsigned int irq;
	DECLARE_BITMAP(irqs, 64) = { BITMAP_FROM_U64(irq_mask) };

	for_each_set_bit(irq, irqs, 64)
		pch_pic_update_irq(s, irq, level);
}

/* called when a irq is triggered in pch pic */
void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level)
{
	u64 mask = BIT(irq);

	spin_lock(&s->lock);
	if (level)
		s->irr |= mask; /* set irr */
	else {
		/*
		 * In edge triggered mode, 0 does not mean to clear irq
		 * The irr register variable is cleared when cpu writes to the
		 * PCH_PIC_CLEAR_START address area
		 */
		if (s->edge & mask) {
			spin_unlock(&s->lock);
			return;
		}
		s->irr &= ~mask;
	}
	pch_pic_update_irq(s, irq, level);
	spin_unlock(&s->lock);
}

/* msi irq handler */
int pch_msi_set_irq(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e, int level)
{
	u64 msg_addr = (((u64)e->msi.address_hi) << 32) | e->msi.address_lo;

	if (cpu_has_msgint && kvm->arch.dmsintc &&
		msg_addr >= kvm->arch.dmsintc->msg_addr_base &&
		msg_addr < (kvm->arch.dmsintc->msg_addr_base + kvm->arch.dmsintc->msg_addr_size)) {
		return dmsintc_set_irq(kvm, msg_addr, e->msi.data, level);
	}

	eiointc_set_irq(kvm->arch.eiointc, e->msi.data, level);

	return 0;
}

static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val)
{
	int offset;
	u64 data = 0;
	void *ptemp;

	offset = addr - s->pch_pic_base;
	offset -= offset & 7;

	spin_lock(&s->lock);
	switch (offset) {
	case PCH_PIC_INT_ID_START ... PCH_PIC_INT_ID_END:
		data = s->id.data;
		break;
	case PCH_PIC_MASK_START ... PCH_PIC_MASK_END:
		data = s->mask;
		break;
	case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END:
		/* read htmsi enable reg */
		data = s->htmsi_en;
		break;
	case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END:
		/* read edge enable reg */
		data = s->edge;
		break;
	case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END:

Annotation

Implementation Notes