aboutsummaryrefslogtreecommitdiff
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.c257
1 files changed, 118 insertions, 139 deletions
diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c
index edb7ee0..e8667ce 100644
--- a/hw/intc/spapr_xive_kvm.c
+++ b/hw/intc/spapr_xive_kvm.c
@@ -73,54 +73,54 @@ static void kvm_cpu_disable_all(void)
* XIVE Thread Interrupt Management context (KVM)
*/
-void kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp)
+int kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp)
{
SpaprXive *xive = SPAPR_XIVE(tctx->xptr);
uint64_t state[2];
int ret;
- /* The KVM XIVE device is not in use yet */
- if (xive->fd == -1) {
- return;
- }
+ assert(xive->fd != -1);
/* word0 and word1 of the OS ring. */
state[0] = *((uint64_t *) &tctx->regs[TM_QW1_OS]);
ret = kvm_set_one_reg(tctx->cs, KVM_REG_PPC_VP_STATE, state);
if (ret != 0) {
- error_setg_errno(errp, errno,
+ error_setg_errno(errp, -ret,
"XIVE: could not restore KVM state of CPU %ld",
kvm_arch_vcpu_id(tctx->cs));
+ return ret;
}
+
+ return 0;
}
-void kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp)
+int kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp)
{
SpaprXive *xive = SPAPR_XIVE(tctx->xptr);
uint64_t state[2] = { 0 };
int ret;
- /* The KVM XIVE device is not in use */
- if (xive->fd == -1) {
- return;
- }
+ assert(xive->fd != -1);
ret = kvm_get_one_reg(tctx->cs, KVM_REG_PPC_VP_STATE, state);
if (ret != 0) {
- error_setg_errno(errp, errno,
+ error_setg_errno(errp, -ret,
"XIVE: could not capture KVM state of CPU %ld",
kvm_arch_vcpu_id(tctx->cs));
- return;
+ return ret;
}
/* word0 and word1 of the OS ring. */
*((uint64_t *) &tctx->regs[TM_QW1_OS]) = state[0];
+
+ return 0;
}
typedef struct {
XiveTCTX *tctx;
- Error *err;
+ Error **errp;
+ int ret;
} XiveCpuGetState;
static void kvmppc_xive_cpu_do_synchronize_state(CPUState *cpu,
@@ -128,14 +128,14 @@ static void kvmppc_xive_cpu_do_synchronize_state(CPUState *cpu,
{
XiveCpuGetState *s = arg.host_ptr;
- kvmppc_xive_cpu_get_state(s->tctx, &s->err);
+ s->ret = kvmppc_xive_cpu_get_state(s->tctx, s->errp);
}
-void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp)
+int kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp)
{
XiveCpuGetState s = {
.tctx = tctx,
- .err = NULL,
+ .errp = errp,
};
/*
@@ -144,26 +144,21 @@ void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp)
run_on_cpu(tctx->cs, kvmppc_xive_cpu_do_synchronize_state,
RUN_ON_CPU_HOST_PTR(&s));
- if (s.err) {
- error_propagate(errp, s.err);
- return;
- }
+ return s.ret;
}
-void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
+int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
{
+ ERRP_GUARD();
SpaprXive *xive = SPAPR_XIVE(tctx->xptr);
unsigned long vcpu_id;
int ret;
- /* The KVM XIVE device is not in use */
- if (xive->fd == -1) {
- return;
- }
+ assert(xive->fd != -1);
/* Check if CPU was hot unplugged and replugged. */
if (kvm_cpu_is_enabled(tctx->cs)) {
- return;
+ return 0;
}
vcpu_id = kvm_arch_vcpu_id(tctx->cs);
@@ -171,28 +166,26 @@ void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
ret = kvm_vcpu_enable_cap(tctx->cs, KVM_CAP_PPC_IRQ_XIVE, 0, xive->fd,
vcpu_id, 0);
if (ret < 0) {
- Error *local_err = NULL;
-
- error_setg(&local_err,
- "XIVE: unable to connect CPU%ld to KVM device: %s",
- vcpu_id, strerror(errno));
- if (errno == ENOSPC) {
- error_append_hint(&local_err, "Try -smp maxcpus=N with N < %u\n",
+ error_setg_errno(errp, -ret,
+ "XIVE: unable to connect CPU%ld to KVM device",
+ vcpu_id);
+ if (ret == -ENOSPC) {
+ error_append_hint(errp, "Try -smp maxcpus=N with N < %u\n",
MACHINE(qdev_get_machine())->smp.max_cpus);
}
- error_propagate(errp, local_err);
- return;
+ return ret;
}
kvm_cpu_enable(tctx->cs);
+ return 0;
}
/*
* XIVE Interrupt Source (KVM)
*/
-void kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas,
- Error **errp)
+int kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas,
+ Error **errp)
{
uint32_t end_idx;
uint32_t end_blk;
@@ -201,7 +194,6 @@ void kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas,
bool masked;
uint32_t eisn;
uint64_t kvm_src;
- Error *local_err = NULL;
assert(xive_eas_is_valid(eas));
@@ -221,12 +213,8 @@ void kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas,
kvm_src |= ((uint64_t)eisn << KVM_XIVE_SOURCE_EISN_SHIFT) &
KVM_XIVE_SOURCE_EISN_MASK;
- kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE_CONFIG, lisn,
- &kvm_src, true, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
+ return kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE_CONFIG, lisn,
+ &kvm_src, true, errp);
}
void kvmppc_xive_sync_source(SpaprXive *xive, uint32_t lisn, Error **errp)
@@ -245,10 +233,7 @@ int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
uint64_t state = 0;
- /* The KVM XIVE device is not in use */
- if (xive->fd == -1) {
- return -ENODEV;
- }
+ assert(xive->fd != -1);
if (xive_source_irq_is_lsi(xsrc, srcno)) {
state |= KVM_XIVE_LEVEL_SENSITIVE;
@@ -261,24 +246,25 @@ int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
true, errp);
}
-static void kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp)
+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++) {
- Error *local_err = NULL;
+ int ret;
if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}
- kvmppc_xive_source_reset_one(xsrc, i, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
+ ret = kvmppc_xive_source_reset_one(xsrc, i, errp);
+ if (ret < 0) {
+ return ret;
}
}
+
+ return 0;
}
/*
@@ -381,15 +367,15 @@ void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val)
/*
* sPAPR XIVE interrupt controller (KVM)
*/
-void kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk,
- uint32_t end_idx, XiveEND *end,
- Error **errp)
+int kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk,
+ uint32_t end_idx, XiveEND *end,
+ Error **errp)
{
struct kvm_ppc_xive_eq kvm_eq = { 0 };
uint64_t kvm_eq_idx;
uint8_t priority;
uint32_t server;
- Error *local_err = NULL;
+ int ret;
assert(xive_end_is_valid(end));
@@ -401,11 +387,10 @@ void kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk,
kvm_eq_idx |= server << KVM_XIVE_EQ_SERVER_SHIFT &
KVM_XIVE_EQ_SERVER_MASK;
- kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_EQ_CONFIG, kvm_eq_idx,
- &kvm_eq, false, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
+ ret = kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_EQ_CONFIG, kvm_eq_idx,
+ &kvm_eq, false, errp);
+ if (ret < 0) {
+ return ret;
}
/*
@@ -415,17 +400,18 @@ void kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk,
*/
end->w1 = xive_set_field32(END_W1_GENERATION, 0ul, kvm_eq.qtoggle) |
xive_set_field32(END_W1_PAGE_OFF, 0ul, kvm_eq.qindex);
+
+ return 0;
}
-void kvmppc_xive_set_queue_config(SpaprXive *xive, uint8_t end_blk,
- uint32_t end_idx, XiveEND *end,
- Error **errp)
+int kvmppc_xive_set_queue_config(SpaprXive *xive, uint8_t end_blk,
+ uint32_t end_idx, XiveEND *end,
+ Error **errp)
{
struct kvm_ppc_xive_eq kvm_eq = { 0 };
uint64_t kvm_eq_idx;
uint8_t priority;
uint32_t server;
- Error *local_err = NULL;
/*
* Build the KVM state from the local END structure.
@@ -463,12 +449,9 @@ void kvmppc_xive_set_queue_config(SpaprXive *xive, uint8_t end_blk,
kvm_eq_idx |= server << KVM_XIVE_EQ_SERVER_SHIFT &
KVM_XIVE_EQ_SERVER_MASK;
- kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_EQ_CONFIG, kvm_eq_idx,
- &kvm_eq, true, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
+ return
+ kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_EQ_CONFIG, kvm_eq_idx,
+ &kvm_eq, true, errp);
}
void kvmppc_xive_reset(SpaprXive *xive, Error **errp)
@@ -477,23 +460,24 @@ void kvmppc_xive_reset(SpaprXive *xive, Error **errp)
NULL, true, errp);
}
-static void kvmppc_xive_get_queues(SpaprXive *xive, Error **errp)
+static int kvmppc_xive_get_queues(SpaprXive *xive, Error **errp)
{
- Error *local_err = NULL;
int i;
+ int ret;
for (i = 0; i < xive->nr_ends; i++) {
if (!xive_end_is_valid(&xive->endt[i])) {
continue;
}
- kvmppc_xive_get_queue_config(xive, SPAPR_XIVE_BLOCK_ID, i,
- &xive->endt[i], &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
+ ret = kvmppc_xive_get_queue_config(xive, SPAPR_XIVE_BLOCK_ID, i,
+ &xive->endt[i], errp);
+ if (ret < 0) {
+ return ret;
}
}
+
+ return 0;
}
/*
@@ -592,10 +576,7 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running,
void kvmppc_xive_synchronize_state(SpaprXive *xive, Error **errp)
{
- /* The KVM XIVE device is not in use */
- if (xive->fd == -1) {
- return;
- }
+ assert(xive->fd != -1);
/*
* When the VM is stopped, the sources are masked and the previous
@@ -621,19 +602,17 @@ void kvmppc_xive_synchronize_state(SpaprXive *xive, Error **errp)
int kvmppc_xive_pre_save(SpaprXive *xive)
{
Error *local_err = NULL;
+ int ret;
- /* The KVM XIVE device is not in use */
- if (xive->fd == -1) {
- return 0;
- }
+ assert(xive->fd != -1);
/* EAT: there is no extra state to query from KVM */
/* ENDT */
- kvmppc_xive_get_queues(xive, &local_err);
- if (local_err) {
+ ret = kvmppc_xive_get_queues(xive, &local_err);
+ if (ret < 0) {
error_report_err(local_err);
- return -1;
+ return ret;
}
return 0;
@@ -650,6 +629,7 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id)
Error *local_err = NULL;
CPUState *cs;
int i;
+ int ret;
/* The KVM XIVE device should be in use */
assert(xive->fd != -1);
@@ -660,11 +640,10 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id)
continue;
}
- kvmppc_xive_set_queue_config(xive, SPAPR_XIVE_BLOCK_ID, i,
- &xive->endt[i], &local_err);
- if (local_err) {
- error_report_err(local_err);
- return -1;
+ ret = kvmppc_xive_set_queue_config(xive, SPAPR_XIVE_BLOCK_ID, i,
+ &xive->endt[i], &local_err);
+ if (ret < 0) {
+ goto fail;
}
}
@@ -679,16 +658,14 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id)
* previously set in KVM. Since we don't do that for all interrupts
* at reset time anymore, let's do it now.
*/
- kvmppc_xive_source_reset_one(&xive->source, i, &local_err);
- if (local_err) {
- error_report_err(local_err);
- return -1;
+ ret = kvmppc_xive_source_reset_one(&xive->source, i, &local_err);
+ if (ret < 0) {
+ goto fail;
}
- kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err);
- if (local_err) {
- error_report_err(local_err);
- return -1;
+ ret = kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err);
+ if (ret < 0) {
+ goto fail;
}
}
@@ -705,17 +682,21 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id)
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
- kvmppc_xive_cpu_set_state(spapr_cpu_state(cpu)->tctx, &local_err);
- if (local_err) {
- error_report_err(local_err);
- return -1;
+ ret = kvmppc_xive_cpu_set_state(spapr_cpu_state(cpu)->tctx, &local_err);
+ if (ret < 0) {
+ goto fail;
}
}
/* The source states will be restored when the machine starts running */
return 0;
+
+fail:
+ error_report_err(local_err);
+ return ret;
}
+/* Returns MAP_FAILED on error and sets errno */
static void *kvmppc_xive_mmap(SpaprXive *xive, int pgoff, size_t len,
Error **errp)
{
@@ -726,7 +707,6 @@ static void *kvmppc_xive_mmap(SpaprXive *xive, int pgoff, size_t len,
pgoff << page_shift);
if (addr == MAP_FAILED) {
error_setg_errno(errp, errno, "XIVE: unable to set memory mapping");
- return NULL;
}
return addr;
@@ -741,10 +721,12 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
{
SpaprXive *xive = SPAPR_XIVE(intc);
XiveSource *xsrc = &xive->source;
- Error *local_err = NULL;
- size_t esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs;
+ size_t esb_len = xive_source_esb_len(xsrc);
size_t tima_len = 4ull << TM_SHIFT;
CPUState *cs;
+ int fd;
+ void *addr;
+ int ret;
/*
* The KVM XIVE device already in use. This is the case when
@@ -760,18 +742,20 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
}
/* First, create the KVM XIVE device */
- xive->fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_XIVE, false);
- if (xive->fd < 0) {
- error_setg_errno(errp, -xive->fd, "XIVE: error creating KVM device");
+ fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_XIVE, false);
+ if (fd < 0) {
+ error_setg_errno(errp, -fd, "XIVE: error creating KVM device");
return -1;
}
+ xive->fd = fd;
/* Tell KVM about the # of VCPUs we may have */
if (kvm_device_check_attr(xive->fd, KVM_DEV_XIVE_GRP_CTRL,
KVM_DEV_XIVE_NR_SERVERS)) {
- if (kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_CTRL,
- KVM_DEV_XIVE_NR_SERVERS, &nr_servers, true,
- &local_err)) {
+ ret = kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_CTRL,
+ KVM_DEV_XIVE_NR_SERVERS, &nr_servers, true,
+ errp);
+ if (ret < 0) {
goto fail;
}
}
@@ -779,14 +763,14 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
/*
* 1. Source ESB pages - KVM mapping
*/
- xsrc->esb_mmap = kvmppc_xive_mmap(xive, KVM_XIVE_ESB_PAGE_OFFSET, esb_len,
- &local_err);
- if (local_err) {
+ addr = kvmppc_xive_mmap(xive, KVM_XIVE_ESB_PAGE_OFFSET, esb_len, errp);
+ if (addr == MAP_FAILED) {
goto fail;
}
+ xsrc->esb_mmap = addr;
memory_region_init_ram_device_ptr(&xsrc->esb_mmio_kvm, OBJECT(xsrc),
- "xive.esb", esb_len, xsrc->esb_mmap);
+ "xive.esb-kvm", esb_len, xsrc->esb_mmap);
memory_region_add_subregion_overlap(&xsrc->esb_mmio, 0,
&xsrc->esb_mmio_kvm, 1);
@@ -797,11 +781,12 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
/*
* 3. TIMA pages - KVM mapping
*/
- xive->tm_mmap = kvmppc_xive_mmap(xive, KVM_XIVE_TIMA_PAGE_OFFSET, tima_len,
- &local_err);
- if (local_err) {
+ addr = kvmppc_xive_mmap(xive, KVM_XIVE_TIMA_PAGE_OFFSET, tima_len, errp);
+ if (addr == MAP_FAILED) {
goto fail;
}
+ xive->tm_mmap = addr;
+
memory_region_init_ram_device_ptr(&xive->tm_mmio_kvm, OBJECT(xive),
"xive.tima", tima_len, xive->tm_mmap);
memory_region_add_subregion_overlap(&xive->tm_mmio, 0,
@@ -814,15 +799,15 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
- kvmppc_xive_cpu_connect(spapr_cpu_state(cpu)->tctx, &local_err);
- if (local_err) {
+ ret = kvmppc_xive_cpu_connect(spapr_cpu_state(cpu)->tctx, errp);
+ if (ret < 0) {
goto fail;
}
}
/* Update the KVM sources */
- kvmppc_xive_source_reset(xsrc, &local_err);
- if (local_err) {
+ ret = kvmppc_xive_source_reset(xsrc, errp);
+ if (ret < 0) {
goto fail;
}
@@ -832,7 +817,6 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
return 0;
fail:
- error_propagate(errp, local_err);
kvmppc_xive_disconnect(intc);
return -1;
}
@@ -843,14 +827,11 @@ void kvmppc_xive_disconnect(SpaprInterruptController *intc)
XiveSource *xsrc;
size_t esb_len;
- /* The KVM XIVE device is not in use */
- if (!xive || xive->fd == -1) {
- return;
- }
+ assert(xive->fd != -1);
/* Clear the KVM mapping */
xsrc = &xive->source;
- esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs;
+ esb_len = xive_source_esb_len(xsrc);
if (xsrc->esb_mmap) {
memory_region_del_subregion(&xsrc->esb_mmio, &xsrc->esb_mmio_kvm);
@@ -871,10 +852,8 @@ void kvmppc_xive_disconnect(SpaprInterruptController *intc)
* and removed from the list of devices of the VM. The VCPU
* presenters are also detached from the device.
*/
- if (xive->fd != -1) {
- close(xive->fd);
- xive->fd = -1;
- }
+ close(xive->fd);
+ xive->fd = -1;
kvm_kernel_irqchip = false;
kvm_msi_via_irqfd_allowed = false;