LoongArch: KVM: Add PCHPIC read and write functions
Upstream: no Implementation of IPI interrupt controller address space read and write function simulation. Implement interrupt injection interface under loongarch. Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn> Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
This commit is contained in:
parent
c4f21bdb97
commit
d50ffb8488
|
@ -35,6 +35,22 @@
|
|||
#define KVM_HALT_POLL_NS_DEFAULT 500000
|
||||
#define KVM_REQ_RECORD_STEAL KVM_ARCH_REQ(1)
|
||||
|
||||
/* KVM_IRQ_LINE irq field index values */
|
||||
#define KVM_LOONGARCH_IRQ_TYPE_SHIFT 24
|
||||
#define KVM_LOONGARCH_IRQ_TYPE_MASK 0xff
|
||||
#define KVM_LOONGARCH_IRQ_VCPU_SHIFT 16
|
||||
#define KVM_LOONGARCH_IRQ_VCPU_MASK 0xff
|
||||
#define KVM_LOONGARCH_IRQ_NUM_SHIFT 0
|
||||
#define KVM_LOONGARCH_IRQ_NUM_MASK 0xffff
|
||||
|
||||
/* irq_type field */
|
||||
#define KVM_LOONGARCH_IRQ_TYPE_CPU_IP 0
|
||||
#define KVM_LOONGARCH_IRQ_TYPE_CPU_IO 1
|
||||
#define KVM_LOONGARCH_IRQ_TYPE_HT 2
|
||||
#define KVM_LOONGARCH_IRQ_TYPE_MSI 3
|
||||
#define KVM_LOONGARCH_IRQ_TYPE_IOAPIC 4
|
||||
#define KVM_LOONGARCH_IRQ_TYPE_ROUTE 5
|
||||
|
||||
#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
|
||||
KVM_GUESTDBG_USE_SW_BP | KVM_GUESTDBG_SINGLESTEP)
|
||||
struct kvm_vm_stat {
|
||||
|
@ -45,6 +61,8 @@ struct kvm_vm_stat {
|
|||
u64 ipi_write_exits;
|
||||
u64 extioi_read_exits;
|
||||
u64 extioi_write_exits;
|
||||
u64 pch_pic_read_exits;
|
||||
u64 pch_pic_write_exits;
|
||||
};
|
||||
|
||||
struct kvm_vcpu_stat {
|
||||
|
|
|
@ -8,6 +8,35 @@
|
|||
|
||||
#include <kvm/iodev.h>
|
||||
|
||||
#define PCH_PIC_SIZE 0x3e8
|
||||
|
||||
#define PCH_PIC_INT_ID_START 0x0
|
||||
#define PCH_PIC_INT_ID_END 0x7
|
||||
#define PCH_PIC_MASK_START 0x20
|
||||
#define PCH_PIC_MASK_END 0x27
|
||||
#define PCH_PIC_HTMSI_EN_START 0x40
|
||||
#define PCH_PIC_HTMSI_EN_END 0x47
|
||||
#define PCH_PIC_EDGE_START 0x60
|
||||
#define PCH_PIC_EDGE_END 0x67
|
||||
#define PCH_PIC_CLEAR_START 0x80
|
||||
#define PCH_PIC_CLEAR_END 0x87
|
||||
#define PCH_PIC_AUTO_CTRL0_START 0xc0
|
||||
#define PCH_PIC_AUTO_CTRL0_END 0xc7
|
||||
#define PCH_PIC_AUTO_CTRL1_START 0xe0
|
||||
#define PCH_PIC_AUTO_CTRL1_END 0xe7
|
||||
#define PCH_PIC_ROUTE_ENTRY_START 0x100
|
||||
#define PCH_PIC_ROUTE_ENTRY_END 0x13f
|
||||
#define PCH_PIC_HTMSI_VEC_START 0x200
|
||||
#define PCH_PIC_HTMSI_VEC_END 0x23f
|
||||
#define PCH_PIC_INT_IRR_START 0x380
|
||||
#define PCH_PIC_INT_IRR_END 0x38f
|
||||
#define PCH_PIC_INT_ISR_START 0x3a0
|
||||
#define PCH_PIC_INT_ISR_END 0x3af
|
||||
#define PCH_PIC_POLARITY_START 0x3e0
|
||||
#define PCH_PIC_POLARITY_END 0x3e7
|
||||
#define PCH_PIC_INT_ID_VAL 0x7000000UL
|
||||
#define PCH_PIC_INT_ID_VER 0x1UL
|
||||
|
||||
struct loongarch_pch_pic {
|
||||
spinlock_t lock;
|
||||
struct kvm *kvm;
|
||||
|
@ -26,5 +55,7 @@ struct loongarch_pch_pic {
|
|||
uint64_t pch_pic_base;
|
||||
};
|
||||
|
||||
void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level);
|
||||
void pch_msi_set_irq(struct kvm *kvm, int irq, int level);
|
||||
int kvm_loongarch_register_pch_pic_device(void);
|
||||
#endif /* LOONGARCH_PCH_PIC_H */
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
||||
#define KVM_DIRTY_LOG_PAGE_OFFSET 64
|
||||
#define __KVM_HAVE_IRQ_LINE
|
||||
|
||||
#define KVM_GUESTDBG_USE_SW_BP 0x00010000
|
||||
/*
|
||||
|
|
|
@ -223,9 +223,9 @@ static int kvm_loongarch_ipi_read(struct kvm_vcpu *vcpu,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data)
|
||||
static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data)
|
||||
{
|
||||
int i;
|
||||
int i, ret;
|
||||
uint32_t val = 0, mask = 0;
|
||||
/*
|
||||
* Bit 27-30 is mask for byte writing.
|
||||
|
@ -233,8 +233,11 @@ static void send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data)
|
|||
*/
|
||||
if ((data >> 27) & 0xf) {
|
||||
/* Read the old val */
|
||||
kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val);
|
||||
|
||||
ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val);
|
||||
if (unlikely(ret)) {
|
||||
kvm_err("%s: : read date from addr %llx failed\n", __func__, addr);
|
||||
return ret;
|
||||
}
|
||||
/* Construct the mask by scanning the bit 27-30 */
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (data & (0x1 << (27 + i)))
|
||||
|
@ -245,41 +248,48 @@ static void send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data)
|
|||
}
|
||||
|
||||
val |= ((uint32_t)(data >> 32) & ~mask);
|
||||
kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val);
|
||||
ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val);
|
||||
if (unlikely(ret))
|
||||
kvm_err("%s: : write date to addr %llx failed\n", __func__, addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mail_send(struct kvm *kvm, uint64_t data)
|
||||
static int mail_send(struct kvm *kvm, uint64_t data)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
int cpu, mailbox;
|
||||
int offset;
|
||||
int offset, ret;
|
||||
|
||||
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
|
||||
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
|
||||
if (unlikely(vcpu == NULL)) {
|
||||
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mailbox = ((data & 0xffffffff) >> 2) & 0x7;
|
||||
offset = SMP_MAILBOX + CORE_BUF_20 + mailbox * 4;
|
||||
send_ipi_data(vcpu, offset, data);
|
||||
ret = send_ipi_data(vcpu, offset, data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void any_send(struct kvm *kvm, uint64_t data)
|
||||
static int any_send(struct kvm *kvm, uint64_t data)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
int cpu, offset;
|
||||
int cpu, offset, ret;
|
||||
|
||||
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
|
||||
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
|
||||
if (unlikely(vcpu == NULL)) {
|
||||
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
offset = data & 0xffff;
|
||||
send_ipi_data(vcpu, offset, data);
|
||||
ret = send_ipi_data(vcpu, offset, data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_loongarch_mail_write(struct kvm_vcpu *vcpu,
|
||||
|
@ -287,6 +297,7 @@ static int kvm_loongarch_mail_write(struct kvm_vcpu *vcpu,
|
|||
gpa_t addr, int len, const void *val)
|
||||
{
|
||||
struct loongarch_ipi *ipi;
|
||||
int ret;
|
||||
|
||||
ipi = vcpu->kvm->arch.ipi;
|
||||
if (!ipi) {
|
||||
|
@ -299,16 +310,18 @@ static int kvm_loongarch_mail_write(struct kvm_vcpu *vcpu,
|
|||
|
||||
switch (addr) {
|
||||
case MAIL_SEND_OFFSET:
|
||||
mail_send(vcpu->kvm, *(uint64_t *)val);
|
||||
ret = mail_send(vcpu->kvm, *(uint64_t *)val);
|
||||
break;
|
||||
case ANY_SEND_OFFSET:
|
||||
any_send(vcpu->kvm, *(uint64_t *)val);
|
||||
ret = any_send(vcpu->kvm, *(uint64_t *)val);
|
||||
break;
|
||||
default:
|
||||
kvm_err("%s: invalid addr %llx!\n", __func__, addr);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct kvm_io_device_ops kvm_loongarch_ipi_ops = {
|
||||
|
|
|
@ -8,18 +8,306 @@
|
|||
#include <asm/kvm_vcpu.h>
|
||||
#include <linux/count_zeros.h>
|
||||
|
||||
/* update the isr according to irq level and route irq to extioi */
|
||||
static void pch_pic_update_irq(struct loongarch_pch_pic *s, int irq, int level)
|
||||
{
|
||||
u64 mask = (1 << irq);
|
||||
|
||||
/*
|
||||
* set isr and route irq to extioi and
|
||||
* the route table is in htmsi_vector[]
|
||||
*/
|
||||
if (level) {
|
||||
if (mask & s->irr & ~s->mask) {
|
||||
s->isr |= mask;
|
||||
irq = s->htmsi_vector[irq];
|
||||
extioi_set_irq(s->kvm->arch.extioi, irq, level);
|
||||
}
|
||||
} else {
|
||||
if (mask & s->isr & ~s->irr) {
|
||||
s->isr &= ~mask;
|
||||
irq = s->htmsi_vector[irq];
|
||||
extioi_set_irq(s->kvm->arch.extioi, irq, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* msi irq handler */
|
||||
void pch_msi_set_irq(struct kvm *kvm, int irq, int level)
|
||||
{
|
||||
extioi_set_irq(kvm->arch.extioi, irq, level);
|
||||
}
|
||||
|
||||
/* called when a irq is triggered in pch pic */
|
||||
void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level)
|
||||
{
|
||||
u64 mask = (1 << irq);
|
||||
|
||||
spin_lock(&s->lock);
|
||||
if (level)
|
||||
/* set irr */
|
||||
s->irr |= mask;
|
||||
else {
|
||||
/* 0 level signal in edge triggered irq does not mean to clear irq
|
||||
* The irr register variable is cleared when the cpu writes to the
|
||||
* PCH_PIC_CLEAR_START address area
|
||||
*/
|
||||
if (s->edge & mask) {
|
||||
spin_unlock(&s->lock);
|
||||
return;
|
||||
}
|
||||
s->irr &= ~mask;
|
||||
}
|
||||
pch_pic_update_irq(s, irq, level);
|
||||
spin_unlock(&s->lock);
|
||||
}
|
||||
|
||||
/* update batch irqs, the irq_mask is a bitmap of irqs */
|
||||
static void pch_pic_update_batch_irqs(struct loongarch_pch_pic *s, u64 irq_mask, int level)
|
||||
{
|
||||
int irq, bits;
|
||||
|
||||
/* find each irq by irqs bitmap and update each irq */
|
||||
bits = sizeof(irq_mask) * 8;
|
||||
irq = find_first_bit((void *)&irq_mask, bits);
|
||||
while (irq < bits) {
|
||||
pch_pic_update_irq(s, irq, level);
|
||||
bitmap_clear((void *)&irq_mask, irq, 1);
|
||||
irq = find_first_bit((void *)&irq_mask, bits);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* pch pic register is 64-bit, but it is accessed by 32-bit,
|
||||
* so we use high to get whether low or high 32 bits we want
|
||||
* to read.
|
||||
*/
|
||||
static u32 pch_pic_read_reg(u64 *s, int high)
|
||||
{
|
||||
u64 val = *s;
|
||||
|
||||
/* read the high 32 bits when the high is 1 */
|
||||
return high ? (u32)(val >> 32) : (u32)val;
|
||||
}
|
||||
|
||||
/*
|
||||
* pch pic register is 64-bit, but it is accessed by 32-bit,
|
||||
* so we use high to get whether low or high 32 bits we want
|
||||
* to write.
|
||||
*/
|
||||
static u32 pch_pic_write_reg(u64 *s, int high, u32 v)
|
||||
{
|
||||
u64 val = *s, data = v;
|
||||
|
||||
if (high) {
|
||||
/*
|
||||
* Clear val high 32 bits
|
||||
* write the high 32 bits when the high is 1
|
||||
*/
|
||||
*s = (val << 32 >> 32) | (data << 32);
|
||||
val >>= 32;
|
||||
} else
|
||||
/*
|
||||
* Clear val low 32 bits
|
||||
* write the low 32 bits when the high is 0
|
||||
*/
|
||||
*s = (val >> 32 << 32) | v;
|
||||
|
||||
return (u32)val;
|
||||
}
|
||||
|
||||
static int loongarch_pch_pic_write(struct loongarch_pch_pic *s, gpa_t addr,
|
||||
int len, const void *val)
|
||||
{
|
||||
u32 old, data, offset, index;
|
||||
u64 irq;
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
data = *(u32 *)val;
|
||||
offset = addr - s->pch_pic_base;
|
||||
|
||||
spin_lock(&s->lock);
|
||||
switch (offset) {
|
||||
case PCH_PIC_MASK_START ... PCH_PIC_MASK_END:
|
||||
offset -= PCH_PIC_MASK_START;
|
||||
/* get whether high or low 32 bits we want to write */
|
||||
index = offset >> 2;
|
||||
old = pch_pic_write_reg(&s->mask, index, data);
|
||||
|
||||
/* enable irq when mask value change to 0 */
|
||||
irq = (old & ~data) << (32 * index);
|
||||
pch_pic_update_batch_irqs(s, irq, 1);
|
||||
|
||||
/* disable irq when mask value change to 1 */
|
||||
irq = (~old & data) << (32 * index);
|
||||
pch_pic_update_batch_irqs(s, irq, 0);
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END:
|
||||
offset -= PCH_PIC_HTMSI_EN_START;
|
||||
index = offset >> 2;
|
||||
pch_pic_write_reg(&s->htmsi_en, index, data);
|
||||
break;
|
||||
case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END:
|
||||
offset -= PCH_PIC_EDGE_START;
|
||||
index = offset >> 2;
|
||||
/* 1: edge triggered, 0: level triggered */
|
||||
pch_pic_write_reg(&s->edge, index, data);
|
||||
break;
|
||||
case PCH_PIC_CLEAR_START ... PCH_PIC_CLEAR_END:
|
||||
offset -= PCH_PIC_CLEAR_START;
|
||||
index = offset >> 2;
|
||||
/* write 1 to clear edge irq */
|
||||
old = pch_pic_read_reg(&s->irr, index);
|
||||
/*
|
||||
* get the irq bitmap which is edge triggered and
|
||||
* already set and to be cleared
|
||||
*/
|
||||
irq = old & pch_pic_read_reg(&s->edge, index) & data;
|
||||
/* write irr to the new state where irqs have been cleared */
|
||||
pch_pic_write_reg(&s->irr, index, old & ~irq);
|
||||
/* update cleared irqs */
|
||||
pch_pic_update_batch_irqs(s, irq, 0);
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END:
|
||||
offset -= PCH_PIC_AUTO_CTRL0_START;
|
||||
index = offset >> 2;
|
||||
/* we only use default mode: fixed interrupt distribution mode */
|
||||
pch_pic_write_reg(&s->auto_ctrl0, index, 0);
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END:
|
||||
offset -= PCH_PIC_AUTO_CTRL1_START;
|
||||
index = offset >> 2;
|
||||
/* we only use default mode: fixed interrupt distribution mode */
|
||||
pch_pic_write_reg(&s->auto_ctrl1, index, 0);
|
||||
break;
|
||||
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
offset -= PCH_PIC_ROUTE_ENTRY_START;
|
||||
/* only route to int0: extioi */
|
||||
s->route_entry[offset] = 1;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END:
|
||||
/* route table to extioi */
|
||||
offset -= PCH_PIC_HTMSI_VEC_START;
|
||||
s->htmsi_vector[offset] = (u8)data;
|
||||
break;
|
||||
case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END:
|
||||
offset -= PCH_PIC_POLARITY_START;
|
||||
index = offset >> 2;
|
||||
|
||||
/* we only use defalut value 0: high level triggered */
|
||||
pch_pic_write_reg(&s->polarity, index, 0);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&s->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_loongarch_pch_pic_write(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, const void *val)
|
||||
{
|
||||
return 0;
|
||||
int ret;
|
||||
struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic;
|
||||
|
||||
if (!s) {
|
||||
kvm_err("%s: pch pic irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* statistics of pch pic writing */
|
||||
vcpu->kvm->stat.pch_pic_write_exits++;
|
||||
ret = loongarch_pch_pic_write(s, addr, len, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val)
|
||||
{
|
||||
int offset, index, ret = 0;
|
||||
u32 data = 0;
|
||||
u64 int_id = 0;
|
||||
|
||||
offset = addr - s->pch_pic_base;
|
||||
|
||||
spin_lock(&s->lock);
|
||||
switch (offset) {
|
||||
case PCH_PIC_INT_ID_START ... PCH_PIC_INT_ID_END:
|
||||
/* int id version */
|
||||
int_id |= (u64)PCH_PIC_INT_ID_VER << 32;
|
||||
/* irq number */
|
||||
int_id |= (u64)31 << (32 + 16);
|
||||
/* int id value */
|
||||
int_id |= PCH_PIC_INT_ID_VAL;
|
||||
*(u64 *)val = int_id;
|
||||
break;
|
||||
case PCH_PIC_MASK_START ... PCH_PIC_MASK_END:
|
||||
offset -= PCH_PIC_MASK_START;
|
||||
index = offset >> 2;
|
||||
/* read mask reg */
|
||||
data = pch_pic_read_reg(&s->mask, index);
|
||||
*(u32 *)val = data;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END:
|
||||
offset -= PCH_PIC_HTMSI_EN_START;
|
||||
index = offset >> 2;
|
||||
/* read htmsi enable reg */
|
||||
data = pch_pic_read_reg(&s->htmsi_en, index);
|
||||
*(u32 *)val = data;
|
||||
break;
|
||||
case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END:
|
||||
offset -= PCH_PIC_EDGE_START;
|
||||
index = offset >> 2;
|
||||
/* read edge enable reg */
|
||||
data = pch_pic_read_reg(&s->edge, index);
|
||||
*(u32 *)val = data;
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END:
|
||||
case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END:
|
||||
/* we only use default mode: fixed interrupt distribution mode */
|
||||
*(u32 *)val = 0;
|
||||
break;
|
||||
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
/* only route to int0: extioi */
|
||||
*(u8 *)val = 1;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END:
|
||||
offset -= PCH_PIC_HTMSI_VEC_START;
|
||||
/* read htmsi vector */
|
||||
data = s->htmsi_vector[offset];
|
||||
*(u8 *)val = data;
|
||||
break;
|
||||
case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END:
|
||||
/* we only use defalut value 0: high level triggered */
|
||||
*(u32 *)val = 0;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
spin_unlock(&s->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_loongarch_pch_pic_read(struct kvm_vcpu *vcpu,
|
||||
struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, void *val)
|
||||
{
|
||||
return 0;
|
||||
int ret;
|
||||
struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic;
|
||||
|
||||
if (!s) {
|
||||
kvm_err("%s: pch pic irqchip not valid!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* statistics of pch pic reading */
|
||||
vcpu->kvm->stat.pch_pic_read_exits++;
|
||||
ret = loongarch_pch_pic_read(s, addr, len, val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct kvm_io_device_ops kvm_loongarch_pch_pic_ops = {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/kvm_extioi.h>
|
||||
#include <asm/kvm_pch_pic.h>
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS(),
|
||||
|
@ -104,3 +106,35 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
|
|||
{
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *data,
|
||||
bool line_status)
|
||||
{
|
||||
bool level;
|
||||
struct loongarch_pch_pic *s;
|
||||
int type, vcpu, irq, vcpus, val, ret = 0;
|
||||
|
||||
level = data->level;
|
||||
val = data->irq;
|
||||
s = kvm->arch.pch_pic;
|
||||
vcpus = atomic_read(&kvm->online_vcpus);
|
||||
|
||||
type = (val >> KVM_LOONGARCH_IRQ_TYPE_SHIFT) & KVM_LOONGARCH_IRQ_TYPE_MASK;
|
||||
vcpu = (val >> KVM_LOONGARCH_IRQ_VCPU_SHIFT) & KVM_LOONGARCH_IRQ_VCPU_MASK;
|
||||
irq = (val >> KVM_LOONGARCH_IRQ_NUM_SHIFT) & KVM_LOONGARCH_IRQ_NUM_MASK;
|
||||
|
||||
switch (type) {
|
||||
case KVM_LOONGARCH_IRQ_TYPE_IOAPIC:
|
||||
if (irq < KVM_IRQCHIP_NUM_PINS)
|
||||
pch_pic_set_irq(s, irq, level);
|
||||
else if (irq < 256)
|
||||
pch_msi_set_irq(kvm, irq, level);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue