summaryrefslogtreecommitdiffstats
path: root/hw/intc/spapr_xive_kvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/intc/spapr_xive_kvm.c')
-rw-r--r--hw/intc/spapr_xive_kvm.c102
1 files changed, 84 insertions, 18 deletions
diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c
index e8667ce5f6..66bf4c06fe 100644
--- a/hw/intc/spapr_xive_kvm.c
+++ b/hw/intc/spapr_xive_kvm.c
@@ -36,10 +36,9 @@ typedef struct KVMEnabledCPU {
static QLIST_HEAD(, KVMEnabledCPU)
kvm_enabled_cpus = QLIST_HEAD_INITIALIZER(&kvm_enabled_cpus);
-static bool kvm_cpu_is_enabled(CPUState *cs)
+static bool kvm_cpu_is_enabled(unsigned long vcpu_id)
{
KVMEnabledCPU *enabled_cpu;
- unsigned long vcpu_id = kvm_arch_vcpu_id(cs);
QLIST_FOREACH(enabled_cpu, &kvm_enabled_cpus, node) {
if (enabled_cpu->vcpu_id == vcpu_id) {
@@ -147,6 +146,45 @@ int kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp)
return s.ret;
}
+/*
+ * Allocate the vCPU IPIs from the vCPU context. This will allocate
+ * the XIVE IPI interrupt on the chip on which the vCPU is running.
+ * This gives a better distribution of IPIs when the guest has a lot
+ * of vCPUs. When the vCPUs are pinned, this will make the IPI local
+ * to the chip of the vCPU. It will reduce rerouting between interrupt
+ * controllers and gives better performance.
+ */
+typedef struct {
+ SpaprXive *xive;
+ Error *err;
+ int rc;
+} XiveInitIPI;
+
+static void kvmppc_xive_reset_ipi_on_cpu(CPUState *cs, run_on_cpu_data arg)
+{
+ unsigned long ipi = kvm_arch_vcpu_id(cs);
+ XiveInitIPI *s = arg.host_ptr;
+ uint64_t state = 0;
+
+ s->rc = kvm_device_access(s->xive->fd, KVM_DEV_XIVE_GRP_SOURCE, ipi,
+ &state, true, &s->err);
+}
+
+static int kvmppc_xive_reset_ipi(SpaprXive *xive, CPUState *cs, Error **errp)
+{
+ XiveInitIPI s = {
+ .xive = xive,
+ .err = NULL,
+ .rc = 0,
+ };
+
+ run_on_cpu(cs, kvmppc_xive_reset_ipi_on_cpu, RUN_ON_CPU_HOST_PTR(&s));
+ if (s.err) {
+ error_propagate(errp, s.err);
+ }
+ return s.rc;
+}
+
int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
{
ERRP_GUARD();
@@ -157,7 +195,7 @@ int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
assert(xive->fd != -1);
/* Check if CPU was hot unplugged and replugged. */
- if (kvm_cpu_is_enabled(tctx->cs)) {
+ if (kvm_cpu_is_enabled(kvm_arch_vcpu_id(tctx->cs))) {
return 0;
}
@@ -176,6 +214,12 @@ int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
return ret;
}
+ /* Create/reset the vCPU IPI */
+ ret = kvmppc_xive_reset_ipi(xive, tctx->cs, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
kvm_cpu_enable(tctx->cs);
return 0;
}
@@ -235,6 +279,12 @@ int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
assert(xive->fd != -1);
+ /*
+ * The vCPU IPIs are now allocated in kvmppc_xive_cpu_connect()
+ * and not with all sources in kvmppc_xive_source_reset()
+ */
+ assert(srcno >= SPAPR_XIRQ_BASE);
+
if (xive_source_irq_is_lsi(xsrc, srcno)) {
state |= KVM_XIVE_LEVEL_SENSITIVE;
if (xsrc->status[srcno] & XIVE_STATUS_ASSERTED) {
@@ -246,12 +296,28 @@ int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
true, errp);
}
+/*
+ * To be valid, a source must have been claimed by the machine (valid
+ * entry in the EAS table) and if it is a vCPU IPI, the vCPU should
+ * have been enabled, which means the IPI has been allocated in
+ * kvmppc_xive_cpu_connect().
+ */
+static bool xive_source_is_valid(SpaprXive *xive, int i)
+{
+ return xive_eas_is_valid(&xive->eat[i]) &&
+ (i >= SPAPR_XIRQ_BASE || kvm_cpu_is_enabled(i));
+}
+
static int kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp)
{
SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
int i;
- for (i = 0; i < xsrc->nr_irqs; i++) {
+ /*
+ * Skip the vCPU IPIs. These are created/reset when the vCPUs are
+ * connected in kvmppc_xive_cpu_connect()
+ */
+ for (i = SPAPR_XIRQ_BASE; i < xsrc->nr_irqs; i++) {
int ret;
if (!xive_eas_is_valid(&xive->eat[i])) {
@@ -333,7 +399,7 @@ static void kvmppc_xive_source_get_state(XiveSource *xsrc)
for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq;
- if (!xive_eas_is_valid(&xive->eat[i])) {
+ if (!xive_source_is_valid(xive, i)) {
continue;
}
@@ -516,7 +582,7 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running,
uint8_t pq;
uint8_t old_pq;
- if (!xive_eas_is_valid(&xive->eat[i])) {
+ if (!xive_source_is_valid(xive, i)) {
continue;
}
@@ -544,7 +610,7 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running,
for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq;
- if (!xive_eas_is_valid(&xive->eat[i])) {
+ if (!xive_source_is_valid(xive, i)) {
continue;
}
@@ -647,22 +713,22 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id)
}
}
+ /*
+ * We can only restore the source config if the source has been
+ * previously set in KVM. Since we don't do that at reset time
+ * when restoring a VM, let's do it now.
+ */
+ ret = kvmppc_xive_source_reset(&xive->source, &local_err);
+ if (ret < 0) {
+ goto fail;
+ }
+
/* Restore the EAT */
for (i = 0; i < xive->nr_irqs; i++) {
- if (!xive_eas_is_valid(&xive->eat[i])) {
+ if (!xive_source_is_valid(xive, i)) {
continue;
}
- /*
- * We can only restore the source config if the source has been
- * previously set in KVM. Since we don't do that for all interrupts
- * at reset time anymore, let's do it now.
- */
- ret = kvmppc_xive_source_reset_one(&xive->source, i, &local_err);
- if (ret < 0) {
- goto fail;
- }
-
ret = kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err);
if (ret < 0) {
goto fail;