Commit e2a098b0 authored by Xianglai Li's avatar Xianglai Li
Browse files

LoongArch: KVM: Add EXTIOI user mode read and write functions

LoongArch inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IB8FOC



------------------------------------------

Implements the communication interface between the user mode
program and the kernel in EXTIOI interrupt control simulation,
which is used to obtain or send the simulation data of the
interrupt controller in the user mode process, and is used
in VM migration or VM saving and restoration.

Signed-off-by: default avatarTianrui Zhao <zhaotianrui@loongson.cn>
Signed-off-by: default avatarXianglai Li <lixianglai@loongson.cn>
parent 89457a71
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -116,4 +116,6 @@ struct kvm_iocsr_entry {

#define KVM_DEV_LOONGARCH_IPI_GRP_REGS		0x40000002

#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS	0x40000003

#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
+101 −2
Original line number Diff line number Diff line
@@ -47,6 +47,26 @@ static void extioi_update_irq(struct loongarch_extioi *s, int irq, int level)
	kvm_vcpu_ioctl_interrupt(vcpu, &vcpu_irq);
}

static void extioi_set_sw_coreisr(struct loongarch_extioi *s)
{
	int ipnum, cpu, irq_index, irq_mask, irq;

	for (irq = 0; irq < EXTIOI_IRQS; irq++) {
		ipnum = s->ipmap.reg_u8[irq / 32];
		ipnum = count_trailing_zeros(ipnum);
		ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0;
		irq_index = irq / 32;
		/* length of accessing core isr is 4 bytes */
		irq_mask = 1 << (irq & 0x1f);

		cpu = s->coremap.reg_u8[irq];
		if (!!(s->coreisr.reg_u32[cpu][irq_index] & irq_mask))
			set_bit(irq, s->sw_coreisr[cpu][ipnum]);
		else
			clear_bit(irq, s->sw_coreisr[cpu][ipnum]);
	}
}

void extioi_set_irq(struct loongarch_extioi *s, int irq, int level)
{
	unsigned long *isr = (unsigned long *)s->isr.reg_u8;
@@ -599,16 +619,95 @@ static const struct kvm_io_device_ops kvm_loongarch_extioi_ops = {
	.write	= kvm_loongarch_extioi_write,
};

static int kvm_loongarch_extioi_regs_access(struct kvm_device *dev,
					struct kvm_device_attr *attr,
					bool is_write)
{
	int len, addr;
	void __user *data;
	void *p = NULL;
	struct loongarch_extioi *s;
	unsigned long flags;

	s = dev->kvm->arch.extioi;
	addr = attr->attr;
	data = (void __user *)attr->addr;

	loongarch_ext_irq_lock(s, flags);
	switch (addr) {
	case EXTIOI_NODETYPE_START:
		p = s->nodetype.reg_u8;
		len = sizeof(s->nodetype);
		break;
	case EXTIOI_IPMAP_START:
		p = s->ipmap.reg_u8;
		len = sizeof(s->ipmap);
		break;
	case EXTIOI_ENABLE_START:
		p = s->enable.reg_u8;
		len = sizeof(s->enable);
		break;
	case EXTIOI_BOUNCE_START:
		p = s->bounce.reg_u8;
		len = sizeof(s->bounce);
		break;
	case EXTIOI_ISR_START:
		p = s->isr.reg_u8;
		len = sizeof(s->isr);
		break;
	case EXTIOI_COREISR_START:
		p = s->coreisr.reg_u8;
		len = sizeof(s->coreisr);
		break;
	case EXTIOI_COREMAP_START:
		p = s->coremap.reg_u8;
		len = sizeof(s->coremap);
		break;
	case EXTIOI_SW_COREMAP_FLAG:
		p = s->sw_coremap;
		len = sizeof(s->sw_coremap);
		break;
	default:
		loongarch_ext_irq_unlock(s, flags);
		kvm_err("%s: unknown extioi register, addr = %d\n", __func__, addr);
		return -EINVAL;
	}

	loongarch_ext_irq_unlock(s, flags);

	if (is_write) {
		if (copy_from_user(p, data, len))
			return -EFAULT;
	} else {
		if (copy_to_user(data, p, len))
			return -EFAULT;
	}

	if ((addr == EXTIOI_COREISR_START) && is_write) {
		loongarch_ext_irq_lock(s, flags);
		extioi_set_sw_coreisr(s);
		loongarch_ext_irq_unlock(s, flags);
	}

	return 0;
}

static int kvm_loongarch_extioi_get_attr(struct kvm_device *dev,
				struct kvm_device_attr *attr)
{
	return 0;
	if (attr->group == KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS)
		return kvm_loongarch_extioi_regs_access(dev, attr, false);

	return -EINVAL;
}

static int kvm_loongarch_extioi_set_attr(struct kvm_device *dev,
				struct kvm_device_attr *attr)
{
	return 0;
	if (attr->group == KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS)
		return kvm_loongarch_extioi_regs_access(dev, attr, true);

	return -EINVAL;
}

static void kvm_loongarch_extioi_destroy(struct kvm_device *dev)