mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 23:46:49 +08:00
LoongArch: KVM: Set default return value in KVM IO bus ops
When in-kernel irqchip is enabled, its register area is registered in the KVM IO bus list with API kvm_io_bus_register_dev(). In MMIO/IOCSR register access emulation, kvm_io_bus_read()/kvm_io_bus_write() is called firstly. If it returns 0, it means that the in-kernel irqchip handles the emulation already, else it returns to user-mode VMM and lets VMM emulate the register access. Once in-kernel irqchip is enabled, it should return 0 if the address is within range of the registered KVM IO bus. It should not return to user-mode VMM since VMM does not know how to handle it, and irqchip is handled in kernel already. Here set default return value with 0 in KVM IO bus operations. Signed-off-by: Bibo Mao <maobibo@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
@@ -119,7 +119,7 @@ void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level)
|
||||
static int loongarch_eiointc_read(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
|
||||
gpa_t addr, unsigned long *val)
|
||||
{
|
||||
int index, ret = 0;
|
||||
int index;
|
||||
u64 data = 0;
|
||||
gpa_t offset;
|
||||
|
||||
@@ -150,40 +150,36 @@ static int loongarch_eiointc_read(struct kvm_vcpu *vcpu, struct loongarch_eioint
|
||||
data = s->coremap[index];
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
*val = data;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, void *val)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
unsigned long flags, data, offset;
|
||||
struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
|
||||
|
||||
if (!eiointc) {
|
||||
kvm_err("%s: eiointc irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addr & (len - 1)) {
|
||||
kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = addr & 0x7;
|
||||
addr -= offset;
|
||||
vcpu->stat.eiointc_read_exits++;
|
||||
spin_lock_irqsave(&eiointc->lock, flags);
|
||||
ret = loongarch_eiointc_read(vcpu, eiointc, addr, &data);
|
||||
loongarch_eiointc_read(vcpu, eiointc, addr, &data);
|
||||
spin_unlock_irqrestore(&eiointc->lock, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data = data >> (offset * 8);
|
||||
switch (len) {
|
||||
@@ -208,7 +204,7 @@ static int loongarch_eiointc_write(struct kvm_vcpu *vcpu,
|
||||
struct loongarch_eiointc *s,
|
||||
gpa_t addr, u64 value, u64 field_mask)
|
||||
{
|
||||
int index, irq, ret = 0;
|
||||
int index, irq;
|
||||
u8 cpu;
|
||||
u64 data, old, mask;
|
||||
gpa_t offset;
|
||||
@@ -287,29 +283,27 @@ static int loongarch_eiointc_write(struct kvm_vcpu *vcpu,
|
||||
eiointc_update_sw_coremap(s, index * 8, data, sizeof(data), true);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, const void *val)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
unsigned long flags, value;
|
||||
struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
|
||||
|
||||
if (!eiointc) {
|
||||
kvm_err("%s: eiointc irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addr & (len - 1)) {
|
||||
kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vcpu->stat.eiointc_write_exits++;
|
||||
@@ -317,24 +311,24 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
|
||||
switch (len) {
|
||||
case 1:
|
||||
value = *(unsigned char *)val;
|
||||
ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, 0xFF);
|
||||
loongarch_eiointc_write(vcpu, eiointc, addr, value, 0xFF);
|
||||
break;
|
||||
case 2:
|
||||
value = *(unsigned short *)val;
|
||||
ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, USHRT_MAX);
|
||||
loongarch_eiointc_write(vcpu, eiointc, addr, value, USHRT_MAX);
|
||||
break;
|
||||
case 4:
|
||||
value = *(unsigned int *)val;
|
||||
ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, UINT_MAX);
|
||||
loongarch_eiointc_write(vcpu, eiointc, addr, value, UINT_MAX);
|
||||
break;
|
||||
default:
|
||||
value = *(unsigned long *)val;
|
||||
ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, ULONG_MAX);
|
||||
loongarch_eiointc_write(vcpu, eiointc, addr, value, ULONG_MAX);
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&eiointc->lock, flags);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kvm_io_device_ops kvm_eiointc_ops = {
|
||||
@@ -352,7 +346,7 @@ static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu,
|
||||
|
||||
if (!eiointc) {
|
||||
kvm_err("%s: eiointc irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr -= EIOINTC_VIRT_BASE;
|
||||
@@ -376,28 +370,25 @@ static int kvm_eiointc_virt_write(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, const void *val)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
u32 value = *(u32 *)val;
|
||||
struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
|
||||
|
||||
if (!eiointc) {
|
||||
kvm_err("%s: eiointc irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr -= EIOINTC_VIRT_BASE;
|
||||
spin_lock_irqsave(&eiointc->lock, flags);
|
||||
switch (addr) {
|
||||
case EIOINTC_VIRT_FEATURES:
|
||||
ret = -EPERM;
|
||||
break;
|
||||
case EIOINTC_VIRT_CONFIG:
|
||||
/*
|
||||
* eiointc features can only be set at disabled status
|
||||
*/
|
||||
if ((eiointc->status & BIT(EIOINTC_ENABLE)) && value) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
eiointc->status = value & eiointc->features;
|
||||
@@ -407,7 +398,7 @@ static int kvm_eiointc_virt_write(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
spin_unlock_irqrestore(&eiointc->lock, flags);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kvm_io_device_ops kvm_eiointc_virt_ops = {
|
||||
|
||||
@@ -111,7 +111,7 @@ static int mail_send(struct kvm *kvm, uint64_t data)
|
||||
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
|
||||
if (unlikely(vcpu == NULL)) {
|
||||
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
mailbox = ((data & 0xffffffff) >> 2) & 0x7;
|
||||
offset = IOCSR_IPI_BUF_20 + mailbox * 4;
|
||||
@@ -145,7 +145,7 @@ static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data)
|
||||
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
||||
if (unlikely(ret)) {
|
||||
kvm_err("%s: : read data from addr %llx failed\n", __func__, addr);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
/* Construct the mask by scanning the bit 27-30 */
|
||||
for (i = 0; i < 4; i++) {
|
||||
@@ -162,7 +162,7 @@ static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data)
|
||||
if (unlikely(ret))
|
||||
kvm_err("%s: : write data to addr %llx failed\n", __func__, addr);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int any_send(struct kvm *kvm, uint64_t data)
|
||||
@@ -174,7 +174,7 @@ static int any_send(struct kvm *kvm, uint64_t data)
|
||||
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
|
||||
if (unlikely(vcpu == NULL)) {
|
||||
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
offset = data & 0xffff;
|
||||
|
||||
@@ -183,7 +183,6 @@ static int any_send(struct kvm *kvm, uint64_t data)
|
||||
|
||||
static int loongarch_ipi_readl(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *val)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t offset;
|
||||
uint64_t res = 0;
|
||||
|
||||
@@ -202,33 +201,27 @@ static int loongarch_ipi_readl(struct kvm_vcpu *vcpu, gpa_t addr, int len, void
|
||||
spin_unlock(&vcpu->arch.ipi_state.lock);
|
||||
break;
|
||||
case IOCSR_IPI_SET:
|
||||
res = 0;
|
||||
break;
|
||||
case IOCSR_IPI_CLEAR:
|
||||
res = 0;
|
||||
break;
|
||||
case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7:
|
||||
if (offset + len > IOCSR_IPI_BUF_38 + 8) {
|
||||
kvm_err("%s: invalid offset or len: offset = %d, len = %d\n",
|
||||
__func__, offset, len);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
res = read_mailbox(vcpu, offset, len);
|
||||
break;
|
||||
default:
|
||||
kvm_err("%s: unknown addr: %llx\n", __func__, addr);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
*(uint64_t *)val = res;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, const void *val)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t data;
|
||||
uint32_t offset;
|
||||
|
||||
@@ -239,7 +232,6 @@ static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, cons
|
||||
|
||||
switch (offset) {
|
||||
case IOCSR_IPI_STATUS:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case IOCSR_IPI_EN:
|
||||
spin_lock(&vcpu->arch.ipi_state.lock);
|
||||
@@ -257,7 +249,6 @@ static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, cons
|
||||
if (offset + len > IOCSR_IPI_BUF_38 + 8) {
|
||||
kvm_err("%s: invalid offset or len: offset = %d, len = %d\n",
|
||||
__func__, offset, len);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
write_mailbox(vcpu, offset, data, len);
|
||||
@@ -266,18 +257,17 @@ static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, cons
|
||||
ipi_send(vcpu->kvm, data);
|
||||
break;
|
||||
case IOCSR_MAIL_SEND:
|
||||
ret = mail_send(vcpu->kvm, data);
|
||||
mail_send(vcpu->kvm, data);
|
||||
break;
|
||||
case IOCSR_ANY_SEND:
|
||||
ret = any_send(vcpu->kvm, data);
|
||||
any_send(vcpu->kvm, data);
|
||||
break;
|
||||
default:
|
||||
kvm_err("%s: unknown addr: %llx\n", __func__, addr);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_ipi_read(struct kvm_vcpu *vcpu,
|
||||
|
||||
@@ -74,7 +74,7 @@ void pch_msi_set_irq(struct kvm *kvm, int irq, int level)
|
||||
|
||||
static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val)
|
||||
{
|
||||
int ret = 0, offset;
|
||||
int offset;
|
||||
u64 data = 0;
|
||||
void *ptemp;
|
||||
|
||||
@@ -121,34 +121,32 @@ static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int l
|
||||
data = s->isr;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
spin_unlock(&s->lock);
|
||||
|
||||
if (ret == 0) {
|
||||
offset = (addr - s->pch_pic_base) & 7;
|
||||
data = data >> (offset * 8);
|
||||
memcpy(val, &data, len);
|
||||
}
|
||||
offset = (addr - s->pch_pic_base) & 7;
|
||||
data = data >> (offset * 8);
|
||||
memcpy(val, &data, len);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_pch_pic_read(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, void *val)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic;
|
||||
|
||||
if (!s) {
|
||||
kvm_err("%s: pch pic irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (addr & (len - 1)) {
|
||||
kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* statistics of pch pic reading */
|
||||
@@ -161,7 +159,7 @@ static int kvm_pch_pic_read(struct kvm_vcpu *vcpu,
|
||||
static int loongarch_pch_pic_write(struct loongarch_pch_pic *s, gpa_t addr,
|
||||
int len, const void *val)
|
||||
{
|
||||
int ret = 0, offset;
|
||||
int offset;
|
||||
u64 old, data, mask;
|
||||
void *ptemp;
|
||||
|
||||
@@ -226,29 +224,28 @@ static int loongarch_pch_pic_write(struct loongarch_pch_pic *s, gpa_t addr,
|
||||
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
spin_unlock(&s->lock);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_pch_pic_write(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, const void *val)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic;
|
||||
|
||||
if (!s) {
|
||||
kvm_err("%s: pch pic irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (addr & (len - 1)) {
|
||||
kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* statistics of pch pic writing */
|
||||
|
||||
Reference in New Issue
Block a user