arch/loongarch/kvm/intc/eiointc.c

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

File Facts

System
Linux kernel
Corpus path
arch/loongarch/kvm/intc/eiointc.c
Extension
.c
Size
17097 bytes
Lines
694
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 (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) {
			ipnum = count_trailing_zeros(ipnum);
			ipnum = ipnum < 4 ? ipnum : 0;
		}

		cpuid = ((u8 *)s->coremap)[irq];
		vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid);
		if (!vcpu)
			continue;

		cpu = vcpu->vcpu_id;
		if (test_bit(irq, (unsigned long *)s->coreisr[cpu]))
			__set_bit(irq, s->sw_coreisr[cpu][ipnum]);
		else
			__clear_bit(irq, s->sw_coreisr[cpu][ipnum]);
	}
}

static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level)
{
	int ipnum, cpu, found;
	struct kvm_vcpu *vcpu;
	struct kvm_interrupt vcpu_irq;

	ipnum = (s->ipmap >> (irq / 32 * 8)) & 0xff;
	if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) {
		ipnum = count_trailing_zeros(ipnum);
		ipnum = ipnum < 4 ? ipnum : 0;
	}

	cpu = s->sw_coremap[irq];
	vcpu = kvm_get_vcpu_by_id(s->kvm, cpu);
	if (unlikely(vcpu == NULL)) {
		kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
		return;
	}

	if (level) {
		/* if not enable return false */
		if (!test_bit(irq, (unsigned long *)s->enable))
			return;
		__set_bit(irq, (unsigned long *)s->coreisr[cpu]);
		found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS);
		__set_bit(irq, s->sw_coreisr[cpu][ipnum]);
	} else {
		__clear_bit(irq, (unsigned long *)s->coreisr[cpu]);
		__clear_bit(irq, s->sw_coreisr[cpu][ipnum]);
		found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS);
	}

	if (found < EIOINTC_IRQS)
		return; /* other irq is handling, needn't update parent irq */

	vcpu_irq.irq = level ? (INT_HWI0 + ipnum) : -(INT_HWI0 + ipnum);
	kvm_vcpu_ioctl_interrupt(vcpu, &vcpu_irq);
}

static inline void eiointc_update_sw_coremap(struct loongarch_eiointc *s,
					int irq, u64 val, u32 len, bool notify)
{
	int i, cpu, cpuid;
	struct kvm_vcpu *vcpu;

	for (i = 0; i < len; i++) {
		cpuid = val & 0xff;
		val = val >> 8;

		if (!(s->status & BIT(EIOINTC_ENABLE_CPU_ENCODE))) {
			cpuid = ffs(cpuid) - 1;
			cpuid = ((cpuid < 0) || (cpuid >= 4)) ? 0 : cpuid;
		}

		vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid);
		if (!vcpu)
			continue;

		cpu = vcpu->vcpu_id;
		if (s->sw_coremap[irq + i] == cpu)
			continue;

		if (notify && test_bit(irq + i, (unsigned long *)s->isr)) {
			/* lower irq at old cpu and raise irq at new cpu */
			eiointc_update_irq(s, irq + i, 0);
			s->sw_coremap[irq + i] = cpu;
			eiointc_update_irq(s, irq + i, 1);
		} else {
			s->sw_coremap[irq + i] = cpu;
		}
	}
}

Annotation

Implementation Notes