This patch adds XICS emulation code (heavily borrowed from QEMU), and wires
this into kvm_cpu__irq() to fire a CPU IRQ via KVM. A device tree entry is
also added. IPIs work, xics_alloc_irqnum() is added to allocate an external
IRQ (which will later be used by the PHB PCI code) and finally, kvm__irq_line()
can be called to raise an IRQ on XICS.
Signed-off-by: Matt Evans
---
tools/kvm/Makefile |1 +
tools/kvm/powerpc/include/kvm/kvm-arch.h |1 +
tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h |2 +
tools/kvm/powerpc/irq.c | 17 +-
tools/kvm/powerpc/kvm-cpu.c | 11 +
tools/kvm/powerpc/kvm.c | 26 +-
tools/kvm/powerpc/xics.c | 514 ++
tools/kvm/powerpc/xics.h | 23 ++
8 files changed, 589 insertions(+), 6 deletions(-)
create mode 100644 tools/kvm/powerpc/xics.c
create mode 100644 tools/kvm/powerpc/xics.h
diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index 0a576be..0d42acf 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -134,6 +134,7 @@ ifeq ($(uname_M), ppc64)
OBJS+= powerpc/spapr_hcall.o
OBJS+= powerpc/spapr_rtas.o
OBJS+= powerpc/spapr_hvcons.o
+ OBJS+= powerpc/xics.o
ARCH_INCLUDE := powerpc/include
CFLAGS += -m64
LIBS+= -lfdt
diff --git a/tools/kvm/powerpc/include/kvm/kvm-arch.h
b/tools/kvm/powerpc/include/kvm/kvm-arch.h
index 33a3827..e070c3f 100644
--- a/tools/kvm/powerpc/include/kvm/kvm-arch.h
+++ b/tools/kvm/powerpc/include/kvm/kvm-arch.h
@@ -67,6 +67,7 @@ struct kvm {
unsigned long initrd_gra;
unsigned long initrd_size;
const char *name;
+ struct icp_state*icp;
};
/* Helper for the various bits of code that generate FDT nodes */
diff --git a/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
b/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
index 64e4510..c1c6539 100644
--- a/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
+++ b/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
@@ -36,6 +36,8 @@
#define MSR_RI (1UL<<1)
#define MSR_LE (1UL<<0)
+#define POWER7_EXT_IRQ 0
+
struct kvm;
struct kvm_cpu {
diff --git a/tools/kvm/powerpc/irq.c b/tools/kvm/powerpc/irq.c
index 46aa64f..a1047d4 100644
--- a/tools/kvm/powerpc/irq.c
+++ b/tools/kvm/powerpc/irq.c
@@ -21,6 +21,15 @@
#include
#include
+#include "xics.h"
+
+#define XICS_IRQS 1024
+
+/*
+ * FIXME: The code in this file assumes an SPAPR guest, using XICS. Make
+ * generic & cope with multiple PPC platform types.
+ */
+
int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
{
fprintf(stderr, "irq__register_device(%d, [%d], [%d], [%d]\n",
@@ -30,7 +39,13 @@ int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
void irq__init(struct kvm *kvm)
{
- fprintf(stderr, __func__);
+ /*
+* kvm->nr_cpus is now valid; for /now/, pass
+* this to xics_system_init(), which assumes servers
+* are numbered 0..nrcpus. This may not really be true,
+* but it is OK currently.
+*/
+ kvm->icp = xics_system_init(XICS_IRQS, kvm->nrcpus);
}
int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg)
diff --git a/tools/kvm/powerpc/kvm-cpu.c b/tools/kvm/powerpc/kvm-cpu.c
index ef3db4d..5ef1cbf 100644
--- a/tools/kvm/powerpc/kvm-cpu.c
+++ b/tools/kvm/powerpc/kvm-cpu.c
@@ -15,6 +15,7 @@
#include "kvm/kvm.h"
#include "spapr.h"
+#include "xics.h"
#include
#include
@@ -89,6 +90,9 @@ struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long
cpu_id)
*/
vcpu->is_running = true;
+ /* Register with IRQ controller (FIXME, assumes XICS) */
+ xics_cpu_register(vcpu);
+
return vcpu;
}
@@ -141,6 +145,13 @@ void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu)
/* kvm_cpu__irq - set KVM's IRQ flag on this vcpu */
void kvm_cpu__irq(struct kvm_cpu *vcpu, int pin, int level)
{
+ unsigned int virq = level ? KVM_INTERRUPT_SET_LEVEL :
KVM_INTERRUPT_UNSET;
+
+ /* FIXME: POWER-specific */
+ if (pin != POWER7_EXT_IRQ)
+ return;
+ if (ioctl(vcpu->vcpu_fd, KVM_INTERRUPT, &virq) < 0)
+ pr_warning("Could not KVM_INTERRUPT.");
}
void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
diff --git a/tools/kvm/powerpc/kvm.c b/tools/kvm/powerpc/kvm.c
index 06fccef..30443c7 100644
--- a/tools/kvm/powerpc/kvm.c
+++ b/tools/kvm/powerpc/kvm.c
@@ -39,9 +39,13 @@
#define HUGETLBFS_PATH "/var/lib/hugetlbfs/global/pagesize-16MB/"
+#define PHANDLE_XICP 0x
+
static char kern_cmdline[2048];
struct kvm_ext kvm_req_ext[] = {
+ { DEFINE_KVM_EXT(KVM_CAP_PPC_UNSET_IRQ) },
+ { DEFINE_KVM_EXT(KVM_CAP_PPC_IRQ_LEVEL) },
{ 0, 0 }
};
@@ -118,11 +122,6 @@ void kvm__arch_init(struct kvm *kvm, const char *kvm_dev,
const char *hugetlbfs_