Skip to content

Commit 1ad7efa

Browse files
lixianglaichenhuacai
authored andcommitted
LoongArch: KVM: Add EIOINTC user mode read and write functions
Implement the communication interface between the user mode programs and the kernel in EIOINTC interrupt controller simulation, which is used to obtain or send the simulation data of the interrupt controller in the user mode process, and is also used in VM migration or VM saving and restoration. Signed-off-by: Xianglai Li <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent 3956a52 commit 1ad7efa

File tree

2 files changed

+173
-2
lines changed

2 files changed

+173
-2
lines changed

arch/loongarch/include/uapi/asm/kvm.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,16 @@ struct kvm_iocsr_entry {
134134

135135
#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000001
136136

137+
#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000002
138+
139+
#define KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS 0x40000003
140+
#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU 0x0
141+
#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_FEATURE 0x1
142+
#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE 0x2
143+
144+
#define KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL 0x40000004
145+
#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU 0x0
146+
#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE 0x1
147+
#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED 0x3
148+
137149
#endif /* __UAPI_ASM_LOONGARCH_KVM_H */

arch/loongarch/kvm/intc/eiointc.c

Lines changed: 161 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -781,16 +781,175 @@ static const struct kvm_io_device_ops kvm_eiointc_virt_ops = {
781781
.write = kvm_eiointc_virt_write,
782782
};
783783

784+
static int kvm_eiointc_ctrl_access(struct kvm_device *dev,
785+
struct kvm_device_attr *attr)
786+
{
787+
int ret = 0;
788+
unsigned long flags;
789+
unsigned long type = (unsigned long)attr->attr;
790+
u32 i, start_irq;
791+
void __user *data;
792+
struct loongarch_eiointc *s = dev->kvm->arch.eiointc;
793+
794+
data = (void __user *)attr->addr;
795+
spin_lock_irqsave(&s->lock, flags);
796+
switch (type) {
797+
case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU:
798+
if (copy_from_user(&s->num_cpu, data, 4))
799+
ret = -EFAULT;
800+
break;
801+
case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE:
802+
if (copy_from_user(&s->features, data, 4))
803+
ret = -EFAULT;
804+
if (!(s->features & BIT(EIOINTC_HAS_VIRT_EXTENSION)))
805+
s->status |= BIT(EIOINTC_ENABLE);
806+
break;
807+
case KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED:
808+
eiointc_set_sw_coreisr(s);
809+
for (i = 0; i < (EIOINTC_IRQS / 4); i++) {
810+
start_irq = i * 4;
811+
eiointc_update_sw_coremap(s, start_irq,
812+
(void *)&s->coremap.reg_u32[i], sizeof(u32), false);
813+
}
814+
break;
815+
default:
816+
break;
817+
}
818+
spin_unlock_irqrestore(&s->lock, flags);
819+
820+
return ret;
821+
}
822+
823+
static int kvm_eiointc_regs_access(struct kvm_device *dev,
824+
struct kvm_device_attr *attr,
825+
bool is_write)
826+
{
827+
int addr, cpuid, offset, ret = 0;
828+
unsigned long flags;
829+
void *p = NULL;
830+
void __user *data;
831+
struct loongarch_eiointc *s;
832+
833+
s = dev->kvm->arch.eiointc;
834+
addr = attr->attr;
835+
cpuid = addr >> 16;
836+
addr &= 0xffff;
837+
data = (void __user *)attr->addr;
838+
switch (addr) {
839+
case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
840+
offset = (addr - EIOINTC_NODETYPE_START) / 4;
841+
p = &s->nodetype.reg_u32[offset];
842+
break;
843+
case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
844+
offset = (addr - EIOINTC_IPMAP_START) / 4;
845+
p = &s->ipmap.reg_u32[offset];
846+
break;
847+
case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
848+
offset = (addr - EIOINTC_ENABLE_START) / 4;
849+
p = &s->enable.reg_u32[offset];
850+
break;
851+
case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
852+
offset = (addr - EIOINTC_BOUNCE_START) / 4;
853+
p = &s->bounce.reg_u32[offset];
854+
break;
855+
case EIOINTC_ISR_START ... EIOINTC_ISR_END:
856+
offset = (addr - EIOINTC_ISR_START) / 4;
857+
p = &s->isr.reg_u32[offset];
858+
break;
859+
case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
860+
offset = (addr - EIOINTC_COREISR_START) / 4;
861+
p = &s->coreisr.reg_u32[cpuid][offset];
862+
break;
863+
case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
864+
offset = (addr - EIOINTC_COREMAP_START) / 4;
865+
p = &s->coremap.reg_u32[offset];
866+
break;
867+
default:
868+
kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr);
869+
return -EINVAL;
870+
}
871+
872+
spin_lock_irqsave(&s->lock, flags);
873+
if (is_write) {
874+
if (copy_from_user(p, data, 4))
875+
ret = -EFAULT;
876+
} else {
877+
if (copy_to_user(data, p, 4))
878+
ret = -EFAULT;
879+
}
880+
spin_unlock_irqrestore(&s->lock, flags);
881+
882+
return ret;
883+
}
884+
885+
static int kvm_eiointc_sw_status_access(struct kvm_device *dev,
886+
struct kvm_device_attr *attr,
887+
bool is_write)
888+
{
889+
int addr, ret = 0;
890+
unsigned long flags;
891+
void *p = NULL;
892+
void __user *data;
893+
struct loongarch_eiointc *s;
894+
895+
s = dev->kvm->arch.eiointc;
896+
addr = attr->attr;
897+
addr &= 0xffff;
898+
899+
data = (void __user *)attr->addr;
900+
switch (addr) {
901+
case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU:
902+
p = &s->num_cpu;
903+
break;
904+
case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_FEATURE:
905+
p = &s->features;
906+
break;
907+
case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE:
908+
p = &s->status;
909+
break;
910+
default:
911+
kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr);
912+
return -EINVAL;
913+
}
914+
spin_lock_irqsave(&s->lock, flags);
915+
if (is_write) {
916+
if (copy_from_user(p, data, 4))
917+
ret = -EFAULT;
918+
} else {
919+
if (copy_to_user(data, p, 4))
920+
ret = -EFAULT;
921+
}
922+
spin_unlock_irqrestore(&s->lock, flags);
923+
924+
return ret;
925+
}
926+
784927
static int kvm_eiointc_get_attr(struct kvm_device *dev,
785928
struct kvm_device_attr *attr)
786929
{
787-
return 0;
930+
switch (attr->group) {
931+
case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS:
932+
return kvm_eiointc_regs_access(dev, attr, false);
933+
case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS:
934+
return kvm_eiointc_sw_status_access(dev, attr, false);
935+
default:
936+
return -EINVAL;
937+
}
788938
}
789939

790940
static int kvm_eiointc_set_attr(struct kvm_device *dev,
791941
struct kvm_device_attr *attr)
792942
{
793-
return 0;
943+
switch (attr->group) {
944+
case KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL:
945+
return kvm_eiointc_ctrl_access(dev, attr);
946+
case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS:
947+
return kvm_eiointc_regs_access(dev, attr, true);
948+
case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS:
949+
return kvm_eiointc_sw_status_access(dev, attr, true);
950+
default:
951+
return -EINVAL;
952+
}
794953
}
795954

796955
static int kvm_eiointc_create(struct kvm_device *dev, u32 type)

0 commit comments

Comments
 (0)