Skip to content

Commit

Permalink
spapr/irq: Only claim VALID interrupts at the KVM level
Browse files Browse the repository at this point in the history
A typical pseries VM with 16 vCPUs, one disk, one network adapater
uses less than 100 interrupts but the whole IRQ number space of the
QEMU machine is allocated at reset time and it is 8K wide. This is
wasting a considerable amount of interrupt numbers in the global IRQ
space which has 1M interrupts per socket on a POWER9.

To optimise the HW resources, only request at the KVM level interrupts
which have been claimed by the guest. This will help to increase the
maximum number of VMs per system and also help supporting nested guests
using the XIVE interrupt mode.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20190911133937.2716-3-clg@kaod.org>
Signed-off-by: Greg Kurz <groug@kaod.org>
Message-Id: <156942766014.1274533.10792048853177121231.stgit@bahia.lan>
[dwg: Folded in fix up from Greg Kurz]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
  • Loading branch information
legoater authored and dgibson committed Oct 4, 2019
1 parent 4a99d40 commit 4c3539d
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 3 deletions.
40 changes: 37 additions & 3 deletions hw/intc/spapr_xive_kvm.c
Expand Up @@ -255,11 +255,16 @@ void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)

static void 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;

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);
Expand Down Expand Up @@ -328,11 +333,18 @@ uint64_t kvmppc_xive_esb_rw(XiveSource *xsrc, int srcno, uint32_t offset,

static void kvmppc_xive_source_get_state(XiveSource *xsrc)
{
SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
int i;

for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq;

if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}

/* Perform a load without side effect to retrieve the PQ bits */
uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);
pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);

/* and save PQ locally */
xive_source_esb_set(xsrc, i, pq);
Expand Down Expand Up @@ -521,9 +533,14 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running,
*/
if (running) {
for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq = xive_source_esb_get(xsrc, i);
uint8_t pq;
uint8_t old_pq;

if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}

pq = xive_source_esb_get(xsrc, i);
old_pq = xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_00 + (pq << 8));

/*
Expand All @@ -545,7 +562,13 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running,
* migration is in progress.
*/
for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);
uint8_t pq;

if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}

pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);

/*
* PQ is set to PENDING to possibly catch a triggered
Expand Down Expand Up @@ -655,6 +678,17 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id)
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.
*/
kvmppc_xive_source_reset_one(&xive->source, i, &local_err);
if (local_err) {
error_report_err(local_err);
return -1;
}

kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err);
if (local_err) {
error_report_err(local_err);
Expand Down
8 changes: 8 additions & 0 deletions hw/intc/xics_kvm.c
Expand Up @@ -190,6 +190,10 @@ void ics_get_kvm_state(ICSState *ics)
for (i = 0; i < ics->nr_irqs; i++) {
ICSIRQState *irq = &ics->irqs[i];

if (ics_irq_free(ics, i)) {
continue;
}

kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
i + ics->offset, &state, false, &error_fatal);

Expand Down Expand Up @@ -301,6 +305,10 @@ int ics_set_kvm_state(ICSState *ics, Error **errp)
Error *local_err = NULL;
int ret;

if (ics_irq_free(ics, i)) {
continue;
}

ret = ics_set_kvm_state_one(ics, i, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
Expand Down

0 comments on commit 4c3539d

Please sign in to comment.