* [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation
@ 2025-07-09 8:02 Bibo Mao
2025-07-09 8:02 ` [PATCH v6 1/8] LoongArch: KVM: Use standard bitops API with eiointc Bibo Mao
` (8 more replies)
0 siblings, 9 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-09 8:02 UTC (permalink / raw)
To: Tianrui Zhao, Huacai Chen, Xianglai Li; +Cc: kvm, loongarch, linux-kernel
This series add generic eiointc 8 bytes access interface, so that 1/2/4/8
bytes access can use the generic 8 bytes access interface. It reduce
about 500 lines redundant code and make eiointc emulation driver
simpler than ever.
---
v5 ... v6:
1. Merge previous patch 5 & 6 into one, patch 7 & 10 into into one and
patch 12 and patch 13 into one.
2. Use sign extension with destination register for IOCSRRD.{B/H/W}
kernel emulation.
v4 ... v5
1. Rebase patch on latest kernel where bugfix of eiointc has been
merged.
2. Add generic eiointc 8 bytes access interface, 1/2/4/8 bytes access
uses generic 8 bytes access interface.
v3 ... v4:
1. Remove patch about enhancement and only keep bugfix relative
patches.
2. Remove INTC indication in the patch title.
3. With access size, keep default case unchanged besides 1/2/4/8 since
here all patches are bugfix
4. Firstly check return value of copy_from_user() with error path,
keep the same order with old patch in patch 4.
v2 ... v3:
1. Add prefix INTC: in title of every patch.
2. Fix array index overflow when emulate register EIOINTC_ENABLE
writing operation.
3. Add address alignment check with eiointc register access operation.
v1 ... v2:
1. Add extra fix in patch 3 and patch 4, add num_cpu validation check
2. Name of stat information keeps unchanged, only move it from VM stat
to vCPU stat.
---
Bibo Mao (8):
LoongArch: KVM: Use standard bitops API with eiointc
LoongArch: KVM: Remove unused parameter len
LoongArch: KVM: Add stat information with kernel irqchip
LoongArch: KVM: Remove never called default case statement
LoongArch: KVM: Use generic function loongarch_eiointc_read()
LoongArch: KVM: Remove some unnecessary local variables
LoongArch: KVM: Replace eiointc_enable_irq() with eiointc_update_irq()
LoongArch: KVM: Add generic function loongarch_eiointc_write()
arch/loongarch/include/asm/kvm_host.h | 12 +-
arch/loongarch/kvm/intc/eiointc.c | 558 ++++----------------------
arch/loongarch/kvm/intc/ipi.c | 28 +-
arch/loongarch/kvm/intc/pch_pic.c | 4 +-
arch/loongarch/kvm/vcpu.c | 8 +-
5 files changed, 102 insertions(+), 508 deletions(-)
base-commit: 733923397fd95405a48f165c9b1fbc8c4b0a4681
--
2.39.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v6 1/8] LoongArch: KVM: Use standard bitops API with eiointc
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
@ 2025-07-09 8:02 ` Bibo Mao
2025-07-09 8:02 ` [PATCH v6 2/8] LoongArch: KVM: Remove unused parameter len Bibo Mao
` (7 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-09 8:02 UTC (permalink / raw)
To: Tianrui Zhao, Huacai Chen, Xianglai Li; +Cc: kvm, loongarch, linux-kernel
Standard bitops APIs such test_bit() is used here, rather than manually
calculate the offset and mask. Also use non-atomic API __set_bit()
and __clear_bit() rather than set_bit() and clear_bit(), since global
spinlock is held already.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/kvm/intc/eiointc.c | 27 +++++++++++----------------
1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index a75f865d6fb9..3cf9894999da 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -9,7 +9,7 @@
static void eiointc_set_sw_coreisr(struct loongarch_eiointc *s)
{
- int ipnum, cpu, cpuid, irq_index, irq_mask, irq;
+ int ipnum, cpu, cpuid, irq;
struct kvm_vcpu *vcpu;
for (irq = 0; irq < EIOINTC_IRQS; irq++) {
@@ -18,8 +18,6 @@ static void eiointc_set_sw_coreisr(struct loongarch_eiointc *s)
ipnum = count_trailing_zeros(ipnum);
ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0;
}
- irq_index = irq / 32;
- irq_mask = BIT(irq & 0x1f);
cpuid = s->coremap.reg_u8[irq];
vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid);
@@ -27,16 +25,16 @@ static void eiointc_set_sw_coreisr(struct loongarch_eiointc *s)
continue;
cpu = vcpu->vcpu_id;
- if (!!(s->coreisr.reg_u32[cpu][irq_index] & irq_mask))
- set_bit(irq, s->sw_coreisr[cpu][ipnum]);
+ if (test_bit(irq, (unsigned long *)s->coreisr.reg_u32[cpu]))
+ __set_bit(irq, s->sw_coreisr[cpu][ipnum]);
else
- clear_bit(irq, s->sw_coreisr[cpu][ipnum]);
+ __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, irq_index, irq_mask;
+ int ipnum, cpu, found;
struct kvm_vcpu *vcpu;
struct kvm_interrupt vcpu_irq;
@@ -48,19 +46,16 @@ static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level)
cpu = s->sw_coremap[irq];
vcpu = kvm_get_vcpu(s->kvm, cpu);
- irq_index = irq / 32;
- irq_mask = BIT(irq & 0x1f);
-
if (level) {
/* if not enable return false */
- if (((s->enable.reg_u32[irq_index]) & irq_mask) == 0)
+ if (!test_bit(irq, (unsigned long *)s->enable.reg_u32))
return;
- s->coreisr.reg_u32[cpu][irq_index] |= irq_mask;
+ __set_bit(irq, (unsigned long *)s->coreisr.reg_u32[cpu]);
found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS);
- set_bit(irq, s->sw_coreisr[cpu][ipnum]);
+ __set_bit(irq, s->sw_coreisr[cpu][ipnum]);
} else {
- s->coreisr.reg_u32[cpu][irq_index] &= ~irq_mask;
- clear_bit(irq, s->sw_coreisr[cpu][ipnum]);
+ __clear_bit(irq, (unsigned long *)s->coreisr.reg_u32[cpu]);
+ __clear_bit(irq, s->sw_coreisr[cpu][ipnum]);
found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS);
}
@@ -110,8 +105,8 @@ void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level)
unsigned long flags;
unsigned long *isr = (unsigned long *)s->isr.reg_u8;
- level ? set_bit(irq, isr) : clear_bit(irq, isr);
spin_lock_irqsave(&s->lock, flags);
+ level ? __set_bit(irq, isr) : __clear_bit(irq, isr);
eiointc_update_irq(s, irq, level);
spin_unlock_irqrestore(&s->lock, flags);
}
--
2.39.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v6 2/8] LoongArch: KVM: Remove unused parameter len
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
2025-07-09 8:02 ` [PATCH v6 1/8] LoongArch: KVM: Use standard bitops API with eiointc Bibo Mao
@ 2025-07-09 8:02 ` Bibo Mao
2025-07-09 8:02 ` [PATCH v6 3/8] LoongArch: KVM: Add stat information with kernel irqchip Bibo Mao
` (6 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-09 8:02 UTC (permalink / raw)
To: Tianrui Zhao, Huacai Chen, Xianglai Li; +Cc: kvm, loongarch, linux-kernel
Parameter len is unused in some functions with eiointc emulation
driver, remove it here.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/kvm/intc/eiointc.c | 32 +++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index 3cf9894999da..acd975ce9608 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -131,7 +131,7 @@ static inline void eiointc_enable_irq(struct kvm_vcpu *vcpu,
}
static int loongarch_eiointc_readb(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
- gpa_t addr, int len, void *val)
+ gpa_t addr, void *val)
{
int index, ret = 0;
u8 data = 0;
@@ -173,7 +173,7 @@ static int loongarch_eiointc_readb(struct kvm_vcpu *vcpu, struct loongarch_eioin
}
static int loongarch_eiointc_readw(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
- gpa_t addr, int len, void *val)
+ gpa_t addr, void *val)
{
int index, ret = 0;
u16 data = 0;
@@ -215,7 +215,7 @@ static int loongarch_eiointc_readw(struct kvm_vcpu *vcpu, struct loongarch_eioin
}
static int loongarch_eiointc_readl(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
- gpa_t addr, int len, void *val)
+ gpa_t addr, void *val)
{
int index, ret = 0;
u32 data = 0;
@@ -257,7 +257,7 @@ static int loongarch_eiointc_readl(struct kvm_vcpu *vcpu, struct loongarch_eioin
}
static int loongarch_eiointc_readq(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
- gpa_t addr, int len, void *val)
+ gpa_t addr, void *val)
{
int index, ret = 0;
u64 data = 0;
@@ -320,16 +320,16 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
spin_lock_irqsave(&eiointc->lock, flags);
switch (len) {
case 1:
- ret = loongarch_eiointc_readb(vcpu, eiointc, addr, len, val);
+ ret = loongarch_eiointc_readb(vcpu, eiointc, addr, val);
break;
case 2:
- ret = loongarch_eiointc_readw(vcpu, eiointc, addr, len, val);
+ ret = loongarch_eiointc_readw(vcpu, eiointc, addr, val);
break;
case 4:
- ret = loongarch_eiointc_readl(vcpu, eiointc, addr, len, val);
+ ret = loongarch_eiointc_readl(vcpu, eiointc, addr, val);
break;
case 8:
- ret = loongarch_eiointc_readq(vcpu, eiointc, addr, len, val);
+ ret = loongarch_eiointc_readq(vcpu, eiointc, addr, val);
break;
default:
WARN_ONCE(1, "%s: Abnormal address access: addr 0x%llx, size %d\n",
@@ -342,7 +342,7 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
static int loongarch_eiointc_writeb(struct kvm_vcpu *vcpu,
struct loongarch_eiointc *s,
- gpa_t addr, int len, const void *val)
+ gpa_t addr, const void *val)
{
int index, irq, bits, ret = 0;
u8 cpu;
@@ -421,7 +421,7 @@ static int loongarch_eiointc_writeb(struct kvm_vcpu *vcpu,
static int loongarch_eiointc_writew(struct kvm_vcpu *vcpu,
struct loongarch_eiointc *s,
- gpa_t addr, int len, const void *val)
+ gpa_t addr, const void *val)
{
int i, index, irq, bits, ret = 0;
u8 cpu;
@@ -506,7 +506,7 @@ static int loongarch_eiointc_writew(struct kvm_vcpu *vcpu,
static int loongarch_eiointc_writel(struct kvm_vcpu *vcpu,
struct loongarch_eiointc *s,
- gpa_t addr, int len, const void *val)
+ gpa_t addr, const void *val)
{
int i, index, irq, bits, ret = 0;
u8 cpu;
@@ -591,7 +591,7 @@ static int loongarch_eiointc_writel(struct kvm_vcpu *vcpu,
static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
struct loongarch_eiointc *s,
- gpa_t addr, int len, const void *val)
+ gpa_t addr, const void *val)
{
int i, index, irq, bits, ret = 0;
u8 cpu;
@@ -696,16 +696,16 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
spin_lock_irqsave(&eiointc->lock, flags);
switch (len) {
case 1:
- ret = loongarch_eiointc_writeb(vcpu, eiointc, addr, len, val);
+ ret = loongarch_eiointc_writeb(vcpu, eiointc, addr, val);
break;
case 2:
- ret = loongarch_eiointc_writew(vcpu, eiointc, addr, len, val);
+ ret = loongarch_eiointc_writew(vcpu, eiointc, addr, val);
break;
case 4:
- ret = loongarch_eiointc_writel(vcpu, eiointc, addr, len, val);
+ ret = loongarch_eiointc_writel(vcpu, eiointc, addr, val);
break;
case 8:
- ret = loongarch_eiointc_writeq(vcpu, eiointc, addr, len, val);
+ ret = loongarch_eiointc_writeq(vcpu, eiointc, addr, val);
break;
default:
WARN_ONCE(1, "%s: Abnormal address access: addr 0x%llx, size %d\n",
--
2.39.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v6 3/8] LoongArch: KVM: Add stat information with kernel irqchip
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
2025-07-09 8:02 ` [PATCH v6 1/8] LoongArch: KVM: Use standard bitops API with eiointc Bibo Mao
2025-07-09 8:02 ` [PATCH v6 2/8] LoongArch: KVM: Remove unused parameter len Bibo Mao
@ 2025-07-09 8:02 ` Bibo Mao
2025-07-09 8:02 ` [PATCH v6 4/8] LoongArch: KVM: Remove never called default case statement Bibo Mao
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-09 8:02 UTC (permalink / raw)
To: Tianrui Zhao, Huacai Chen, Xianglai Li; +Cc: kvm, loongarch, linux-kernel
Move stat information about kernel irqchip from VM to vCPU, since
all vm exiting events should be vCPU relative. And also add entry
with structure kvm_vcpu_stats_desc[], so that it can display with
directory /sys/kernel/debug/kvm.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/include/asm/kvm_host.h | 12 ++++++------
arch/loongarch/kvm/intc/eiointc.c | 4 ++--
arch/loongarch/kvm/intc/ipi.c | 28 ++++-----------------------
arch/loongarch/kvm/intc/pch_pic.c | 4 ++--
arch/loongarch/kvm/vcpu.c | 8 +++++++-
5 files changed, 21 insertions(+), 35 deletions(-)
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index a3c4cc46c892..0cecbd038bb3 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -50,12 +50,6 @@ struct kvm_vm_stat {
struct kvm_vm_stat_generic generic;
u64 pages;
u64 hugepages;
- u64 ipi_read_exits;
- u64 ipi_write_exits;
- u64 eiointc_read_exits;
- u64 eiointc_write_exits;
- u64 pch_pic_read_exits;
- u64 pch_pic_write_exits;
};
struct kvm_vcpu_stat {
@@ -65,6 +59,12 @@ struct kvm_vcpu_stat {
u64 cpucfg_exits;
u64 signal_exits;
u64 hypercall_exits;
+ u64 ipi_read_exits;
+ u64 ipi_write_exits;
+ u64 eiointc_read_exits;
+ u64 eiointc_write_exits;
+ u64 pch_pic_read_exits;
+ u64 pch_pic_write_exits;
};
#define KVM_MEM_HUGEPAGE_CAPABLE (1UL << 0)
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index acd975ce9608..92bae1dea8eb 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -316,7 +316,7 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
return -EINVAL;
}
- vcpu->kvm->stat.eiointc_read_exits++;
+ vcpu->stat.eiointc_read_exits++;
spin_lock_irqsave(&eiointc->lock, flags);
switch (len) {
case 1:
@@ -692,7 +692,7 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
return -EINVAL;
}
- vcpu->kvm->stat.eiointc_write_exits++;
+ vcpu->stat.eiointc_write_exits++;
spin_lock_irqsave(&eiointc->lock, flags);
switch (len) {
case 1:
diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c
index fe734dc062ed..e658d5b37c04 100644
--- a/arch/loongarch/kvm/intc/ipi.c
+++ b/arch/loongarch/kvm/intc/ipi.c
@@ -268,36 +268,16 @@ static int kvm_ipi_read(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
{
- int ret;
- struct loongarch_ipi *ipi;
-
- ipi = vcpu->kvm->arch.ipi;
- if (!ipi) {
- kvm_err("%s: ipi irqchip not valid!\n", __func__);
- return -EINVAL;
- }
- ipi->kvm->stat.ipi_read_exits++;
- ret = loongarch_ipi_readl(vcpu, addr, len, val);
-
- return ret;
+ vcpu->stat.ipi_read_exits++;
+ return loongarch_ipi_readl(vcpu, addr, len, val);
}
static int kvm_ipi_write(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, const void *val)
{
- int ret;
- struct loongarch_ipi *ipi;
-
- ipi = vcpu->kvm->arch.ipi;
- if (!ipi) {
- kvm_err("%s: ipi irqchip not valid!\n", __func__);
- return -EINVAL;
- }
- ipi->kvm->stat.ipi_write_exits++;
- ret = loongarch_ipi_writel(vcpu, addr, len, val);
-
- return ret;
+ vcpu->stat.ipi_write_exits++;
+ return loongarch_ipi_writel(vcpu, addr, len, val);
}
static const struct kvm_io_device_ops kvm_ipi_ops = {
diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c
index 08fce845f668..6f00ffe05c54 100644
--- a/arch/loongarch/kvm/intc/pch_pic.c
+++ b/arch/loongarch/kvm/intc/pch_pic.c
@@ -196,7 +196,7 @@ static int kvm_pch_pic_read(struct kvm_vcpu *vcpu,
}
/* statistics of pch pic reading */
- vcpu->kvm->stat.pch_pic_read_exits++;
+ vcpu->stat.pch_pic_read_exits++;
ret = loongarch_pch_pic_read(s, addr, len, val);
return ret;
@@ -303,7 +303,7 @@ static int kvm_pch_pic_write(struct kvm_vcpu *vcpu,
}
/* statistics of pch pic writing */
- vcpu->kvm->stat.pch_pic_write_exits++;
+ vcpu->stat.pch_pic_write_exits++;
ret = loongarch_pch_pic_write(s, addr, len, val);
return ret;
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 5af32ec62cb1..d1b8c50941ca 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -20,7 +20,13 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
STATS_DESC_COUNTER(VCPU, idle_exits),
STATS_DESC_COUNTER(VCPU, cpucfg_exits),
STATS_DESC_COUNTER(VCPU, signal_exits),
- STATS_DESC_COUNTER(VCPU, hypercall_exits)
+ STATS_DESC_COUNTER(VCPU, hypercall_exits),
+ STATS_DESC_COUNTER(VCPU, ipi_read_exits),
+ STATS_DESC_COUNTER(VCPU, ipi_write_exits),
+ STATS_DESC_COUNTER(VCPU, eiointc_read_exits),
+ STATS_DESC_COUNTER(VCPU, eiointc_write_exits),
+ STATS_DESC_COUNTER(VCPU, pch_pic_read_exits),
+ STATS_DESC_COUNTER(VCPU, pch_pic_write_exits)
};
const struct kvm_stats_header kvm_vcpu_stats_header = {
--
2.39.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v6 4/8] LoongArch: KVM: Remove never called default case statement
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
` (2 preceding siblings ...)
2025-07-09 8:02 ` [PATCH v6 3/8] LoongArch: KVM: Add stat information with kernel irqchip Bibo Mao
@ 2025-07-09 8:02 ` Bibo Mao
2025-07-09 8:02 ` [PATCH v6 5/8] LoongArch: KVM: Use generic function loongarch_eiointc_read() Bibo Mao
` (4 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-09 8:02 UTC (permalink / raw)
To: Tianrui Zhao, Huacai Chen, Xianglai Li; +Cc: kvm, loongarch, linux-kernel
IOCSR instruction supports 1/2/4/8 bytes access, len must be 1/2/4/8
bytes from iocsr exit emulation function kvm_emu_iocsr(), remove the
default case in switch case statements.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/kvm/intc/eiointc.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index 92bae1dea8eb..137cd3adca80 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -328,12 +328,9 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
case 4:
ret = loongarch_eiointc_readl(vcpu, eiointc, addr, val);
break;
- case 8:
+ default:
ret = loongarch_eiointc_readq(vcpu, eiointc, addr, val);
break;
- default:
- WARN_ONCE(1, "%s: Abnormal address access: addr 0x%llx, size %d\n",
- __func__, addr, len);
}
spin_unlock_irqrestore(&eiointc->lock, flags);
@@ -704,12 +701,9 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
case 4:
ret = loongarch_eiointc_writel(vcpu, eiointc, addr, val);
break;
- case 8:
+ default:
ret = loongarch_eiointc_writeq(vcpu, eiointc, addr, val);
break;
- default:
- WARN_ONCE(1, "%s: Abnormal address access: addr 0x%llx, size %d\n",
- __func__, addr, len);
}
spin_unlock_irqrestore(&eiointc->lock, flags);
--
2.39.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v6 5/8] LoongArch: KVM: Use generic function loongarch_eiointc_read()
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
` (3 preceding siblings ...)
2025-07-09 8:02 ` [PATCH v6 4/8] LoongArch: KVM: Remove never called default case statement Bibo Mao
@ 2025-07-09 8:02 ` Bibo Mao
2025-07-09 8:02 ` [PATCH v6 6/8] LoongArch: KVM: Remove some unnecessary local variables Bibo Mao
` (3 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-09 8:02 UTC (permalink / raw)
To: Tianrui Zhao, Huacai Chen, Xianglai Li; +Cc: kvm, loongarch, linux-kernel
Generic read function loongarch_eiointc_read() is used for 1/2/4/8
bytes read access. It reads 8 bytes from emulated software state
and shift right from address offset.
Also the similar with kvm_complete_iocsr_read(), destination register
of IOCSRRD.{B/H/W} is sign extension from byte/half word/word.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/kvm/intc/eiointc.c | 153 ++++--------------------------
1 file changed, 17 insertions(+), 136 deletions(-)
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index 137cd3adca80..3e8dc844be76 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -130,134 +130,8 @@ static inline void eiointc_enable_irq(struct kvm_vcpu *vcpu,
}
}
-static int loongarch_eiointc_readb(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
- gpa_t addr, void *val)
-{
- int index, ret = 0;
- u8 data = 0;
- gpa_t offset;
-
- offset = addr - EIOINTC_BASE;
- switch (offset) {
- case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
- index = offset - EIOINTC_NODETYPE_START;
- data = s->nodetype.reg_u8[index];
- break;
- case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
- index = offset - EIOINTC_IPMAP_START;
- data = s->ipmap.reg_u8[index];
- break;
- case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
- index = offset - EIOINTC_ENABLE_START;
- data = s->enable.reg_u8[index];
- break;
- case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
- index = offset - EIOINTC_BOUNCE_START;
- data = s->bounce.reg_u8[index];
- break;
- case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
- index = offset - EIOINTC_COREISR_START;
- data = s->coreisr.reg_u8[vcpu->vcpu_id][index];
- break;
- case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
- index = offset - EIOINTC_COREMAP_START;
- data = s->coremap.reg_u8[index];
- break;
- default:
- ret = -EINVAL;
- break;
- }
- *(u8 *)val = data;
-
- return ret;
-}
-
-static int loongarch_eiointc_readw(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
- gpa_t addr, void *val)
-{
- int index, ret = 0;
- u16 data = 0;
- gpa_t offset;
-
- offset = addr - EIOINTC_BASE;
- switch (offset) {
- case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
- index = (offset - EIOINTC_NODETYPE_START) >> 1;
- data = s->nodetype.reg_u16[index];
- break;
- case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
- index = (offset - EIOINTC_IPMAP_START) >> 1;
- data = s->ipmap.reg_u16[index];
- break;
- case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
- index = (offset - EIOINTC_ENABLE_START) >> 1;
- data = s->enable.reg_u16[index];
- break;
- case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
- index = (offset - EIOINTC_BOUNCE_START) >> 1;
- data = s->bounce.reg_u16[index];
- break;
- case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
- index = (offset - EIOINTC_COREISR_START) >> 1;
- data = s->coreisr.reg_u16[vcpu->vcpu_id][index];
- break;
- case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
- index = (offset - EIOINTC_COREMAP_START) >> 1;
- data = s->coremap.reg_u16[index];
- break;
- default:
- ret = -EINVAL;
- break;
- }
- *(u16 *)val = data;
-
- return ret;
-}
-
-static int loongarch_eiointc_readl(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
- gpa_t addr, void *val)
-{
- int index, ret = 0;
- u32 data = 0;
- gpa_t offset;
-
- offset = addr - EIOINTC_BASE;
- switch (offset) {
- case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
- index = (offset - EIOINTC_NODETYPE_START) >> 2;
- data = s->nodetype.reg_u32[index];
- break;
- case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
- index = (offset - EIOINTC_IPMAP_START) >> 2;
- data = s->ipmap.reg_u32[index];
- break;
- case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
- index = (offset - EIOINTC_ENABLE_START) >> 2;
- data = s->enable.reg_u32[index];
- break;
- case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
- index = (offset - EIOINTC_BOUNCE_START) >> 2;
- data = s->bounce.reg_u32[index];
- break;
- case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
- index = (offset - EIOINTC_COREISR_START) >> 2;
- data = s->coreisr.reg_u32[vcpu->vcpu_id][index];
- break;
- case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
- index = (offset - EIOINTC_COREMAP_START) >> 2;
- data = s->coremap.reg_u32[index];
- break;
- default:
- ret = -EINVAL;
- break;
- }
- *(u32 *)val = data;
-
- return ret;
-}
-
-static int loongarch_eiointc_readq(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
- gpa_t addr, void *val)
+static int loongarch_eiointc_read(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
+ gpa_t addr, unsigned long *val)
{
int index, ret = 0;
u64 data = 0;
@@ -293,7 +167,7 @@ static int loongarch_eiointc_readq(struct kvm_vcpu *vcpu, struct loongarch_eioin
ret = -EINVAL;
break;
}
- *(u64 *)val = data;
+ *val = data;
return ret;
}
@@ -303,7 +177,7 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
gpa_t addr, int len, void *val)
{
int ret = -EINVAL;
- unsigned long flags;
+ unsigned long flags, data, offset;
struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
if (!eiointc) {
@@ -317,24 +191,31 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
}
vcpu->stat.eiointc_read_exits++;
+ offset = addr & 0x7;
+ addr -= offset;
spin_lock_irqsave(&eiointc->lock, flags);
+ ret = loongarch_eiointc_read(vcpu, eiointc, addr, &data);
+ spin_unlock_irqrestore(&eiointc->lock, flags);
+ if (ret)
+ return ret;
+
+ data = data >> (offset * 8);
switch (len) {
case 1:
- ret = loongarch_eiointc_readb(vcpu, eiointc, addr, val);
+ *(long *)val = (s8)data;
break;
case 2:
- ret = loongarch_eiointc_readw(vcpu, eiointc, addr, val);
+ *(long *)val = (s16)data;
break;
case 4:
- ret = loongarch_eiointc_readl(vcpu, eiointc, addr, val);
+ *(long *)val = (s32)data;
break;
default:
- ret = loongarch_eiointc_readq(vcpu, eiointc, addr, val);
+ *(long *)val = (long)data;
break;
}
- spin_unlock_irqrestore(&eiointc->lock, flags);
- return ret;
+ return 0;
}
static int loongarch_eiointc_writeb(struct kvm_vcpu *vcpu,
--
2.39.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v6 6/8] LoongArch: KVM: Remove some unnecessary local variables
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
` (4 preceding siblings ...)
2025-07-09 8:02 ` [PATCH v6 5/8] LoongArch: KVM: Use generic function loongarch_eiointc_read() Bibo Mao
@ 2025-07-09 8:02 ` Bibo Mao
2025-07-09 8:02 ` [PATCH v6 7/8] LoongArch: KVM: Replace eiointc_enable_irq() with eiointc_update_irq() Bibo Mao
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-09 8:02 UTC (permalink / raw)
To: Tianrui Zhao, Huacai Chen, Xianglai Li; +Cc: kvm, loongarch, linux-kernel
Local variable coreisr and old_coreisr is replaced with data and
old_data, and the latter is widely used in other places.
Also local variable offset is removed and addr is used directly.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/kvm/intc/eiointc.c | 31 ++++++++++++++-----------------
1 file changed, 14 insertions(+), 17 deletions(-)
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index 3e8dc844be76..bed5f7bdc8b4 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -474,15 +474,13 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
int i, index, irq, bits, ret = 0;
u8 cpu;
u64 data, old_data;
- u64 coreisr, old_coreisr;
- gpa_t offset;
data = *(u64 *)val;
- offset = addr - EIOINTC_BASE;
+ addr -= EIOINTC_BASE;
- switch (offset) {
+ switch (addr) {
case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
- index = (offset - EIOINTC_NODETYPE_START) >> 3;
+ index = (addr - EIOINTC_NODETYPE_START) >> 3;
s->nodetype.reg_u64[index] = data;
break;
case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
@@ -490,11 +488,11 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
* ipmap cannot be set at runtime, can be set only at the beginning
* of irqchip driver, need not update upper irq level
*/
- index = (offset - EIOINTC_IPMAP_START) >> 3;
+ index = (addr - EIOINTC_IPMAP_START) >> 3;
s->ipmap.reg_u64 = data;
break;
case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
- index = (offset - EIOINTC_ENABLE_START) >> 3;
+ index = (addr - EIOINTC_ENABLE_START) >> 3;
old_data = s->enable.reg_u64[index];
s->enable.reg_u64[index] = data;
/*
@@ -518,28 +516,27 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
break;
case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
/* do not emulate hw bounced irq routing */
- index = (offset - EIOINTC_BOUNCE_START) >> 3;
+ index = (addr - EIOINTC_BOUNCE_START) >> 3;
s->bounce.reg_u64[index] = data;
break;
case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
- index = (offset - EIOINTC_COREISR_START) >> 3;
+ index = (addr - EIOINTC_COREISR_START) >> 3;
/* use attrs to get current cpu index */
cpu = vcpu->vcpu_id;
- coreisr = data;
- old_coreisr = s->coreisr.reg_u64[cpu][index];
+ old_data = s->coreisr.reg_u64[cpu][index];
/* write 1 to clear interrupt */
- s->coreisr.reg_u64[cpu][index] = old_coreisr & ~coreisr;
- coreisr &= old_coreisr;
+ s->coreisr.reg_u64[cpu][index] = old_data & ~data;
+ data &= old_data;
bits = sizeof(data) * 8;
- irq = find_first_bit((void *)&coreisr, bits);
+ irq = find_first_bit((void *)&data, bits);
while (irq < bits) {
eiointc_update_irq(s, irq + index * bits, 0);
- bitmap_clear((void *)&coreisr, irq, 1);
- irq = find_first_bit((void *)&coreisr, bits);
+ bitmap_clear((void *)&data, irq, 1);
+ irq = find_first_bit((void *)&data, bits);
}
break;
case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
- irq = offset - EIOINTC_COREMAP_START;
+ irq = addr - EIOINTC_COREMAP_START;
index = irq >> 3;
s->coremap.reg_u64[index] = data;
eiointc_update_sw_coremap(s, irq, data, sizeof(data), true);
--
2.39.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v6 7/8] LoongArch: KVM: Replace eiointc_enable_irq() with eiointc_update_irq()
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
` (5 preceding siblings ...)
2025-07-09 8:02 ` [PATCH v6 6/8] LoongArch: KVM: Remove some unnecessary local variables Bibo Mao
@ 2025-07-09 8:02 ` Bibo Mao
2025-07-09 8:02 ` [PATCH v6 8/8] LoongArch: KVM: Add generic function loongarch_eiointc_write() Bibo Mao
2025-07-16 10:19 ` [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Huacai Chen
8 siblings, 0 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-09 8:02 UTC (permalink / raw)
To: Tianrui Zhao, Huacai Chen, Xianglai Li; +Cc: kvm, loongarch, linux-kernel
Function eiointc_enable_irq() checks mask value with char type, and
call eiointc_update_irq() eventually. Function eiointc_update_irq()
will update one single irq status directly.
Here it can check mask value with unsigned long type and call function
eiointc_update_irq(), that is simple and direct.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/kvm/intc/eiointc.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index bed5f7bdc8b4..edcf87055b3c 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -471,7 +471,7 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
struct loongarch_eiointc *s,
gpa_t addr, const void *val)
{
- int i, index, irq, bits, ret = 0;
+ int index, irq, ret = 0;
u8 cpu;
u64 data, old_data;
@@ -500,18 +500,20 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
* update irq when isr is set.
*/
data = s->enable.reg_u64[index] & ~old_data & s->isr.reg_u64[index];
- for (i = 0; i < sizeof(data); i++) {
- u8 mask = (data >> (i * 8)) & 0xff;
- eiointc_enable_irq(vcpu, s, index * 8 + i, mask, 1);
+ while (data) {
+ irq = __ffs(data);
+ eiointc_update_irq(s, irq + index * 64, 1);
+ data &= ~BIT_ULL(irq);
}
/*
* 0: disable irq.
* update irq when isr is set.
*/
data = ~s->enable.reg_u64[index] & old_data & s->isr.reg_u64[index];
- for (i = 0; i < sizeof(data); i++) {
- u8 mask = (data >> (i * 8)) & 0xff;
- eiointc_enable_irq(vcpu, s, index * 8 + i, mask, 0);
+ while (data) {
+ irq = __ffs(data);
+ eiointc_update_irq(s, irq + index * 64, 0);
+ data &= ~BIT_ULL(irq);
}
break;
case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
@@ -527,12 +529,10 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
/* write 1 to clear interrupt */
s->coreisr.reg_u64[cpu][index] = old_data & ~data;
data &= old_data;
- bits = sizeof(data) * 8;
- irq = find_first_bit((void *)&data, bits);
- while (irq < bits) {
- eiointc_update_irq(s, irq + index * bits, 0);
- bitmap_clear((void *)&data, irq, 1);
- irq = find_first_bit((void *)&data, bits);
+ while (data) {
+ irq = __ffs(data);
+ eiointc_update_irq(s, irq + index * 64, 0);
+ data &= ~BIT_ULL(irq);
}
break;
case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
--
2.39.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v6 8/8] LoongArch: KVM: Add generic function loongarch_eiointc_write()
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
` (6 preceding siblings ...)
2025-07-09 8:02 ` [PATCH v6 7/8] LoongArch: KVM: Replace eiointc_enable_irq() with eiointc_update_irq() Bibo Mao
@ 2025-07-09 8:02 ` Bibo Mao
2025-07-16 10:19 ` [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Huacai Chen
8 siblings, 0 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-09 8:02 UTC (permalink / raw)
To: Tianrui Zhao, Huacai Chen, Xianglai Li; +Cc: kvm, loongarch, linux-kernel
With all eiointc iocsr register write operation with 1/2/4/8 bytes
size, generic function loongarch_eiointc_write() is used here. And
function loongarch_eiointc_writeb(), loongarch_eiointc_writew(),
loongarch_eiointc_writel() are removed.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/kvm/intc/eiointc.c | 329 ++++--------------------------
1 file changed, 35 insertions(+), 294 deletions(-)
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index edcf87055b3c..cac59b10fa79 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -111,25 +111,6 @@ void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level)
spin_unlock_irqrestore(&s->lock, flags);
}
-static inline void eiointc_enable_irq(struct kvm_vcpu *vcpu,
- struct loongarch_eiointc *s, int index, u8 mask, int level)
-{
- u8 val;
- int irq;
-
- val = mask & s->isr.reg_u8[index];
- irq = ffs(val);
- while (irq != 0) {
- /*
- * enable bit change from 0 to 1,
- * need to update irq by pending bits
- */
- eiointc_update_irq(s, irq - 1 + index * 8, level);
- val &= ~BIT(irq - 1);
- irq = ffs(val);
- }
-}
-
static int loongarch_eiointc_read(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
gpa_t addr, unsigned long *val)
{
@@ -218,288 +199,42 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
return 0;
}
-static int loongarch_eiointc_writeb(struct kvm_vcpu *vcpu,
- struct loongarch_eiointc *s,
- gpa_t addr, const void *val)
-{
- int index, irq, bits, ret = 0;
- u8 cpu;
- u8 data, old_data;
- u8 coreisr, old_coreisr;
- gpa_t offset;
-
- data = *(u8 *)val;
- offset = addr - EIOINTC_BASE;
-
- switch (offset) {
- case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
- index = (offset - EIOINTC_NODETYPE_START);
- s->nodetype.reg_u8[index] = data;
- break;
- case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
- /*
- * ipmap cannot be set at runtime, can be set only at the beginning
- * of irqchip driver, need not update upper irq level
- */
- index = (offset - EIOINTC_IPMAP_START);
- s->ipmap.reg_u8[index] = data;
- break;
- case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
- index = (offset - EIOINTC_ENABLE_START);
- old_data = s->enable.reg_u8[index];
- s->enable.reg_u8[index] = data;
- /*
- * 1: enable irq.
- * update irq when isr is set.
- */
- data = s->enable.reg_u8[index] & ~old_data & s->isr.reg_u8[index];
- eiointc_enable_irq(vcpu, s, index, data, 1);
- /*
- * 0: disable irq.
- * update irq when isr is set.
- */
- data = ~s->enable.reg_u8[index] & old_data & s->isr.reg_u8[index];
- eiointc_enable_irq(vcpu, s, index, data, 0);
- break;
- case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
- /* do not emulate hw bounced irq routing */
- index = offset - EIOINTC_BOUNCE_START;
- s->bounce.reg_u8[index] = data;
- break;
- case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
- index = (offset - EIOINTC_COREISR_START);
- /* use attrs to get current cpu index */
- cpu = vcpu->vcpu_id;
- coreisr = data;
- old_coreisr = s->coreisr.reg_u8[cpu][index];
- /* write 1 to clear interrupt */
- s->coreisr.reg_u8[cpu][index] = old_coreisr & ~coreisr;
- coreisr &= old_coreisr;
- bits = sizeof(data) * 8;
- irq = find_first_bit((void *)&coreisr, bits);
- while (irq < bits) {
- eiointc_update_irq(s, irq + index * bits, 0);
- bitmap_clear((void *)&coreisr, irq, 1);
- irq = find_first_bit((void *)&coreisr, bits);
- }
- break;
- case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
- irq = offset - EIOINTC_COREMAP_START;
- index = irq;
- s->coremap.reg_u8[index] = data;
- eiointc_update_sw_coremap(s, irq, data, sizeof(data), true);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int loongarch_eiointc_writew(struct kvm_vcpu *vcpu,
- struct loongarch_eiointc *s,
- gpa_t addr, const void *val)
-{
- int i, index, irq, bits, ret = 0;
- u8 cpu;
- u16 data, old_data;
- u16 coreisr, old_coreisr;
- gpa_t offset;
-
- data = *(u16 *)val;
- offset = addr - EIOINTC_BASE;
-
- switch (offset) {
- case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
- index = (offset - EIOINTC_NODETYPE_START) >> 1;
- s->nodetype.reg_u16[index] = data;
- break;
- case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
- /*
- * ipmap cannot be set at runtime, can be set only at the beginning
- * of irqchip driver, need not update upper irq level
- */
- index = (offset - EIOINTC_IPMAP_START) >> 1;
- s->ipmap.reg_u16[index] = data;
- break;
- case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
- index = (offset - EIOINTC_ENABLE_START) >> 1;
- old_data = s->enable.reg_u16[index];
- s->enable.reg_u16[index] = data;
- /*
- * 1: enable irq.
- * update irq when isr is set.
- */
- data = s->enable.reg_u16[index] & ~old_data & s->isr.reg_u16[index];
- for (i = 0; i < sizeof(data); i++) {
- u8 mask = (data >> (i * 8)) & 0xff;
- eiointc_enable_irq(vcpu, s, index * 2 + i, mask, 1);
- }
- /*
- * 0: disable irq.
- * update irq when isr is set.
- */
- data = ~s->enable.reg_u16[index] & old_data & s->isr.reg_u16[index];
- for (i = 0; i < sizeof(data); i++) {
- u8 mask = (data >> (i * 8)) & 0xff;
- eiointc_enable_irq(vcpu, s, index * 2 + i, mask, 0);
- }
- break;
- case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
- /* do not emulate hw bounced irq routing */
- index = (offset - EIOINTC_BOUNCE_START) >> 1;
- s->bounce.reg_u16[index] = data;
- break;
- case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
- index = (offset - EIOINTC_COREISR_START) >> 1;
- /* use attrs to get current cpu index */
- cpu = vcpu->vcpu_id;
- coreisr = data;
- old_coreisr = s->coreisr.reg_u16[cpu][index];
- /* write 1 to clear interrupt */
- s->coreisr.reg_u16[cpu][index] = old_coreisr & ~coreisr;
- coreisr &= old_coreisr;
- bits = sizeof(data) * 8;
- irq = find_first_bit((void *)&coreisr, bits);
- while (irq < bits) {
- eiointc_update_irq(s, irq + index * bits, 0);
- bitmap_clear((void *)&coreisr, irq, 1);
- irq = find_first_bit((void *)&coreisr, bits);
- }
- break;
- case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
- irq = offset - EIOINTC_COREMAP_START;
- index = irq >> 1;
- s->coremap.reg_u16[index] = data;
- eiointc_update_sw_coremap(s, irq, data, sizeof(data), true);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int loongarch_eiointc_writel(struct kvm_vcpu *vcpu,
- struct loongarch_eiointc *s,
- gpa_t addr, const void *val)
-{
- int i, index, irq, bits, ret = 0;
- u8 cpu;
- u32 data, old_data;
- u32 coreisr, old_coreisr;
- gpa_t offset;
-
- data = *(u32 *)val;
- offset = addr - EIOINTC_BASE;
-
- switch (offset) {
- case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
- index = (offset - EIOINTC_NODETYPE_START) >> 2;
- s->nodetype.reg_u32[index] = data;
- break;
- case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
- /*
- * ipmap cannot be set at runtime, can be set only at the beginning
- * of irqchip driver, need not update upper irq level
- */
- index = (offset - EIOINTC_IPMAP_START) >> 2;
- s->ipmap.reg_u32[index] = data;
- break;
- case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
- index = (offset - EIOINTC_ENABLE_START) >> 2;
- old_data = s->enable.reg_u32[index];
- s->enable.reg_u32[index] = data;
- /*
- * 1: enable irq.
- * update irq when isr is set.
- */
- data = s->enable.reg_u32[index] & ~old_data & s->isr.reg_u32[index];
- for (i = 0; i < sizeof(data); i++) {
- u8 mask = (data >> (i * 8)) & 0xff;
- eiointc_enable_irq(vcpu, s, index * 4 + i, mask, 1);
- }
- /*
- * 0: disable irq.
- * update irq when isr is set.
- */
- data = ~s->enable.reg_u32[index] & old_data & s->isr.reg_u32[index];
- for (i = 0; i < sizeof(data); i++) {
- u8 mask = (data >> (i * 8)) & 0xff;
- eiointc_enable_irq(vcpu, s, index * 4 + i, mask, 0);
- }
- break;
- case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
- /* do not emulate hw bounced irq routing */
- index = (offset - EIOINTC_BOUNCE_START) >> 2;
- s->bounce.reg_u32[index] = data;
- break;
- case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
- index = (offset - EIOINTC_COREISR_START) >> 2;
- /* use attrs to get current cpu index */
- cpu = vcpu->vcpu_id;
- coreisr = data;
- old_coreisr = s->coreisr.reg_u32[cpu][index];
- /* write 1 to clear interrupt */
- s->coreisr.reg_u32[cpu][index] = old_coreisr & ~coreisr;
- coreisr &= old_coreisr;
- bits = sizeof(data) * 8;
- irq = find_first_bit((void *)&coreisr, bits);
- while (irq < bits) {
- eiointc_update_irq(s, irq + index * bits, 0);
- bitmap_clear((void *)&coreisr, irq, 1);
- irq = find_first_bit((void *)&coreisr, bits);
- }
- break;
- case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
- irq = offset - EIOINTC_COREMAP_START;
- index = irq >> 2;
- s->coremap.reg_u32[index] = data;
- eiointc_update_sw_coremap(s, irq, data, sizeof(data), true);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
+static int loongarch_eiointc_write(struct kvm_vcpu *vcpu,
struct loongarch_eiointc *s,
- gpa_t addr, const void *val)
+ gpa_t addr, u64 value, u64 field_mask)
{
- int index, irq, ret = 0;
+ int index, irq, offset, ret = 0;
u8 cpu;
- u64 data, old_data;
+ u64 data, old, mask;
- data = *(u64 *)val;
- addr -= EIOINTC_BASE;
+ offset = addr & 7;
+ mask = field_mask << (offset * 8);
+ data = (value & field_mask) << (offset * 8);
+ addr -= EIOINTC_BASE + offset;
switch (addr) {
case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
index = (addr - EIOINTC_NODETYPE_START) >> 3;
- s->nodetype.reg_u64[index] = data;
+ old = s->nodetype.reg_u64[index];
+ s->nodetype.reg_u64[index] = (old & ~mask) | data;
break;
case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
/*
* ipmap cannot be set at runtime, can be set only at the beginning
* of irqchip driver, need not update upper irq level
*/
- index = (addr - EIOINTC_IPMAP_START) >> 3;
- s->ipmap.reg_u64 = data;
+ old = s->ipmap.reg_u64;
+ s->ipmap.reg_u64 = (old & ~mask) | data;
break;
case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
index = (addr - EIOINTC_ENABLE_START) >> 3;
- old_data = s->enable.reg_u64[index];
- s->enable.reg_u64[index] = data;
+ old = s->enable.reg_u64[index];
+ s->enable.reg_u64[index] = (old & ~mask) | data;
/*
* 1: enable irq.
* update irq when isr is set.
*/
- data = s->enable.reg_u64[index] & ~old_data & s->isr.reg_u64[index];
+ data = s->enable.reg_u64[index] & ~old & s->isr.reg_u64[index];
while (data) {
irq = __ffs(data);
eiointc_update_irq(s, irq + index * 64, 1);
@@ -509,7 +244,7 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
* 0: disable irq.
* update irq when isr is set.
*/
- data = ~s->enable.reg_u64[index] & old_data & s->isr.reg_u64[index];
+ data = ~s->enable.reg_u64[index] & old & s->isr.reg_u64[index];
while (data) {
irq = __ffs(data);
eiointc_update_irq(s, irq + index * 64, 0);
@@ -519,16 +254,17 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
/* do not emulate hw bounced irq routing */
index = (addr - EIOINTC_BOUNCE_START) >> 3;
- s->bounce.reg_u64[index] = data;
+ old = s->bounce.reg_u64[index];
+ s->bounce.reg_u64[index] = (old & ~mask) | data;
break;
case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
index = (addr - EIOINTC_COREISR_START) >> 3;
/* use attrs to get current cpu index */
cpu = vcpu->vcpu_id;
- old_data = s->coreisr.reg_u64[cpu][index];
+ old = s->coreisr.reg_u64[cpu][index];
/* write 1 to clear interrupt */
- s->coreisr.reg_u64[cpu][index] = old_data & ~data;
- data &= old_data;
+ s->coreisr.reg_u64[cpu][index] = old & ~data;
+ data &= old;
while (data) {
irq = __ffs(data);
eiointc_update_irq(s, irq + index * 64, 0);
@@ -536,10 +272,11 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
}
break;
case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
- irq = addr - EIOINTC_COREMAP_START;
- index = irq >> 3;
- s->coremap.reg_u64[index] = data;
- eiointc_update_sw_coremap(s, irq, data, sizeof(data), true);
+ index = (addr - EIOINTC_COREMAP_START) >> 3;
+ old = s->coremap.reg_u64[index];
+ s->coremap.reg_u64[index] = (old & ~mask) | data;
+ data = s->coremap.reg_u64[index];
+ eiointc_update_sw_coremap(s, index * 8, data, sizeof(data), true);
break;
default:
ret = -EINVAL;
@@ -554,7 +291,7 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
gpa_t addr, int len, const void *val)
{
int ret = -EINVAL;
- unsigned long flags;
+ unsigned long flags, value;
struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
if (!eiointc) {
@@ -571,16 +308,20 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
spin_lock_irqsave(&eiointc->lock, flags);
switch (len) {
case 1:
- ret = loongarch_eiointc_writeb(vcpu, eiointc, addr, val);
+ value = *(unsigned char *)val;
+ ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, 0xFF);
break;
case 2:
- ret = loongarch_eiointc_writew(vcpu, eiointc, addr, val);
+ value = *(unsigned short *)val;
+ ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, USHRT_MAX);
break;
case 4:
- ret = loongarch_eiointc_writel(vcpu, eiointc, addr, val);
+ value = *(unsigned int *)val;
+ ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, UINT_MAX);
break;
default:
- ret = loongarch_eiointc_writeq(vcpu, eiointc, addr, val);
+ value = *(unsigned long *)val;
+ ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, ULONG_MAX);
break;
}
spin_unlock_irqrestore(&eiointc->lock, flags);
--
2.39.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
` (7 preceding siblings ...)
2025-07-09 8:02 ` [PATCH v6 8/8] LoongArch: KVM: Add generic function loongarch_eiointc_write() Bibo Mao
@ 2025-07-16 10:19 ` Huacai Chen
2025-07-17 7:14 ` Bibo Mao
8 siblings, 1 reply; 11+ messages in thread
From: Huacai Chen @ 2025-07-16 10:19 UTC (permalink / raw)
To: Bibo Mao; +Cc: Tianrui Zhao, Xianglai Li, kvm, loongarch, linux-kernel
Applied with some modifications. E.g., Patch6 removes offset, and
Patch8 adds it back, so I combine these two.
Since the code is a little different, it is better to test it again [1].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git/log/?h=loongarch-kvm
Huacai
On Wed, Jul 9, 2025 at 4:02 PM Bibo Mao <maobibo@loongson.cn> wrote:
>
> This series add generic eiointc 8 bytes access interface, so that 1/2/4/8
> bytes access can use the generic 8 bytes access interface. It reduce
> about 500 lines redundant code and make eiointc emulation driver
> simpler than ever.
>
> ---
> v5 ... v6:
> 1. Merge previous patch 5 & 6 into one, patch 7 & 10 into into one and
> patch 12 and patch 13 into one.
> 2. Use sign extension with destination register for IOCSRRD.{B/H/W}
> kernel emulation.
>
> v4 ... v5
> 1. Rebase patch on latest kernel where bugfix of eiointc has been
> merged.
> 2. Add generic eiointc 8 bytes access interface, 1/2/4/8 bytes access
> uses generic 8 bytes access interface.
>
> v3 ... v4:
> 1. Remove patch about enhancement and only keep bugfix relative
> patches.
> 2. Remove INTC indication in the patch title.
> 3. With access size, keep default case unchanged besides 1/2/4/8 since
> here all patches are bugfix
> 4. Firstly check return value of copy_from_user() with error path,
> keep the same order with old patch in patch 4.
>
> v2 ... v3:
> 1. Add prefix INTC: in title of every patch.
> 2. Fix array index overflow when emulate register EIOINTC_ENABLE
> writing operation.
> 3. Add address alignment check with eiointc register access operation.
>
> v1 ... v2:
> 1. Add extra fix in patch 3 and patch 4, add num_cpu validation check
> 2. Name of stat information keeps unchanged, only move it from VM stat
> to vCPU stat.
> ---
> Bibo Mao (8):
> LoongArch: KVM: Use standard bitops API with eiointc
> LoongArch: KVM: Remove unused parameter len
> LoongArch: KVM: Add stat information with kernel irqchip
> LoongArch: KVM: Remove never called default case statement
> LoongArch: KVM: Use generic function loongarch_eiointc_read()
> LoongArch: KVM: Remove some unnecessary local variables
> LoongArch: KVM: Replace eiointc_enable_irq() with eiointc_update_irq()
> LoongArch: KVM: Add generic function loongarch_eiointc_write()
>
> arch/loongarch/include/asm/kvm_host.h | 12 +-
> arch/loongarch/kvm/intc/eiointc.c | 558 ++++----------------------
> arch/loongarch/kvm/intc/ipi.c | 28 +-
> arch/loongarch/kvm/intc/pch_pic.c | 4 +-
> arch/loongarch/kvm/vcpu.c | 8 +-
> 5 files changed, 102 insertions(+), 508 deletions(-)
>
>
> base-commit: 733923397fd95405a48f165c9b1fbc8c4b0a4681
> --
> 2.39.3
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation
2025-07-16 10:19 ` [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Huacai Chen
@ 2025-07-17 7:14 ` Bibo Mao
0 siblings, 0 replies; 11+ messages in thread
From: Bibo Mao @ 2025-07-17 7:14 UTC (permalink / raw)
To: Huacai Chen; +Cc: Tianrui Zhao, Xianglai Li, kvm, loongarch, linux-kernel
On 2025/7/16 下午6:19, Huacai Chen wrote:
> Applied with some modifications. E.g., Patch6 removes offset, and
> Patch8 adds it back, so I combine these two.
>
> Since the code is a little different, it is better to test it again [1].
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git/log/?h=loongarch-kvm
It works well with basic VM operations.
Also looks good from code review side.
Regards
Bibo Mao
>
>
>
> Huacai
>
> On Wed, Jul 9, 2025 at 4:02 PM Bibo Mao <maobibo@loongson.cn> wrote:
>>
>> This series add generic eiointc 8 bytes access interface, so that 1/2/4/8
>> bytes access can use the generic 8 bytes access interface. It reduce
>> about 500 lines redundant code and make eiointc emulation driver
>> simpler than ever.
>>
>> ---
>> v5 ... v6:
>> 1. Merge previous patch 5 & 6 into one, patch 7 & 10 into into one and
>> patch 12 and patch 13 into one.
>> 2. Use sign extension with destination register for IOCSRRD.{B/H/W}
>> kernel emulation.
>>
>> v4 ... v5
>> 1. Rebase patch on latest kernel where bugfix of eiointc has been
>> merged.
>> 2. Add generic eiointc 8 bytes access interface, 1/2/4/8 bytes access
>> uses generic 8 bytes access interface.
>>
>> v3 ... v4:
>> 1. Remove patch about enhancement and only keep bugfix relative
>> patches.
>> 2. Remove INTC indication in the patch title.
>> 3. With access size, keep default case unchanged besides 1/2/4/8 since
>> here all patches are bugfix
>> 4. Firstly check return value of copy_from_user() with error path,
>> keep the same order with old patch in patch 4.
>>
>> v2 ... v3:
>> 1. Add prefix INTC: in title of every patch.
>> 2. Fix array index overflow when emulate register EIOINTC_ENABLE
>> writing operation.
>> 3. Add address alignment check with eiointc register access operation.
>>
>> v1 ... v2:
>> 1. Add extra fix in patch 3 and patch 4, add num_cpu validation check
>> 2. Name of stat information keeps unchanged, only move it from VM stat
>> to vCPU stat.
>> ---
>> Bibo Mao (8):
>> LoongArch: KVM: Use standard bitops API with eiointc
>> LoongArch: KVM: Remove unused parameter len
>> LoongArch: KVM: Add stat information with kernel irqchip
>> LoongArch: KVM: Remove never called default case statement
>> LoongArch: KVM: Use generic function loongarch_eiointc_read()
>> LoongArch: KVM: Remove some unnecessary local variables
>> LoongArch: KVM: Replace eiointc_enable_irq() with eiointc_update_irq()
>> LoongArch: KVM: Add generic function loongarch_eiointc_write()
>>
>> arch/loongarch/include/asm/kvm_host.h | 12 +-
>> arch/loongarch/kvm/intc/eiointc.c | 558 ++++----------------------
>> arch/loongarch/kvm/intc/ipi.c | 28 +-
>> arch/loongarch/kvm/intc/pch_pic.c | 4 +-
>> arch/loongarch/kvm/vcpu.c | 8 +-
>> 5 files changed, 102 insertions(+), 508 deletions(-)
>>
>>
>> base-commit: 733923397fd95405a48f165c9b1fbc8c4b0a4681
>> --
>> 2.39.3
>>
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-07-17 7:16 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-09 8:02 [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Bibo Mao
2025-07-09 8:02 ` [PATCH v6 1/8] LoongArch: KVM: Use standard bitops API with eiointc Bibo Mao
2025-07-09 8:02 ` [PATCH v6 2/8] LoongArch: KVM: Remove unused parameter len Bibo Mao
2025-07-09 8:02 ` [PATCH v6 3/8] LoongArch: KVM: Add stat information with kernel irqchip Bibo Mao
2025-07-09 8:02 ` [PATCH v6 4/8] LoongArch: KVM: Remove never called default case statement Bibo Mao
2025-07-09 8:02 ` [PATCH v6 5/8] LoongArch: KVM: Use generic function loongarch_eiointc_read() Bibo Mao
2025-07-09 8:02 ` [PATCH v6 6/8] LoongArch: KVM: Remove some unnecessary local variables Bibo Mao
2025-07-09 8:02 ` [PATCH v6 7/8] LoongArch: KVM: Replace eiointc_enable_irq() with eiointc_update_irq() Bibo Mao
2025-07-09 8:02 ` [PATCH v6 8/8] LoongArch: KVM: Add generic function loongarch_eiointc_write() Bibo Mao
2025-07-16 10:19 ` [PATCH v6 0/8] LoongArch: KVM: Enhancement with eiointc emulation Huacai Chen
2025-07-17 7:14 ` Bibo Mao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).