Skip to content

Commit

Permalink
KVM: PPC: Book3S HV: XIVE: add a control to initialize a source
Browse files Browse the repository at this point in the history
The XIVE KVM device maintains a list of interrupt sources for the VM
which are allocated in the pool of generic interrupts (IPIs) of the
main XIVE IC controller. These are used for the CPU IPIs as well as
for virtual device interrupts. The IRQ number space is defined by
QEMU.

The XIVE device reuses the source structures of the XICS-on-XIVE
device for the source blocks (2-level tree) and for the source
interrupts. Under XIVE native, the source interrupt caches mostly
configuration information and is less used than under the XICS-on-XIVE
device in which hcalls are still necessary at run-time.

When a source is initialized in KVM, an IPI interrupt source is simply
allocated at the OPAL level and then MASKED. KVM only needs to know
about its type: LSI or MSI.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
  • Loading branch information
legoater authored and paulusmack committed Apr 30, 2019
1 parent eacc56b commit 4131f83
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 4 deletions.
15 changes: 15 additions & 0 deletions Documentation/virtual/kvm/devices/xive.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,18 @@ the legacy interrupt mode, referred as XICS (POWER7/8).

1. KVM_DEV_XIVE_GRP_CTRL
Provides global controls on the device

2. KVM_DEV_XIVE_GRP_SOURCE (write only)
Initializes a new source in the XIVE device and mask it.
Attributes:
Interrupt source number (64-bit)
The kvm_device_attr.addr points to a __u64 value:
bits: | 63 .... 2 | 1 | 0
values: | unused | level | type
- type: 0:MSI 1:LSI
- level: assertion level in case of an LSI.
Errors:
-E2BIG: Interrupt source number is out of range
-ENOMEM: Could not create a new source block
-EFAULT: Invalid user pointer for attr->addr.
-ENXIO: Could not allocate underlying HW interrupt
5 changes: 5 additions & 0 deletions arch/powerpc/include/uapi/asm/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -679,5 +679,10 @@ struct kvm_ppc_cpu_char {

/* POWER9 XIVE Native Interrupt Controller */
#define KVM_DEV_XIVE_GRP_CTRL 1
#define KVM_DEV_XIVE_GRP_SOURCE 2 /* 64-bit source identifier */

/* Layout of 64-bit XIVE source attribute values */
#define KVM_XIVE_LEVEL_SENSITIVE (1ULL << 0)
#define KVM_XIVE_LEVEL_ASSERTED (1ULL << 1)

#endif /* __LINUX_KVM_POWERPC_H */
8 changes: 4 additions & 4 deletions arch/powerpc/kvm/book3s_xive.c
Original file line number Diff line number Diff line change
Expand Up @@ -1480,8 +1480,8 @@ static int xive_get_source(struct kvmppc_xive *xive, long irq, u64 addr)
return 0;
}

static struct kvmppc_xive_src_block *xive_create_src_block(struct kvmppc_xive *xive,
int irq)
struct kvmppc_xive_src_block *kvmppc_xive_create_src_block(
struct kvmppc_xive *xive, int irq)
{
struct kvm *kvm = xive->kvm;
struct kvmppc_xive_src_block *sb;
Expand Down Expand Up @@ -1560,7 +1560,7 @@ static int xive_set_source(struct kvmppc_xive *xive, long irq, u64 addr)
sb = kvmppc_xive_find_source(xive, irq, &idx);
if (!sb) {
pr_devel("No source, creating source block...\n");
sb = xive_create_src_block(xive, irq);
sb = kvmppc_xive_create_src_block(xive, irq);
if (!sb) {
pr_devel("Failed to create block...\n");
return -ENOMEM;
Expand Down Expand Up @@ -1784,7 +1784,7 @@ static void kvmppc_xive_cleanup_irq(u32 hw_num, struct xive_irq_data *xd)
xive_cleanup_irq_data(xd);
}

static void kvmppc_xive_free_sources(struct kvmppc_xive_src_block *sb)
void kvmppc_xive_free_sources(struct kvmppc_xive_src_block *sb)
{
int i;

Expand Down
10 changes: 10 additions & 0 deletions arch/powerpc/kvm/book3s_xive.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
#ifdef CONFIG_KVM_XICS
#include "book3s_xics.h"

/*
* The XIVE Interrupt source numbers are within the range 0 to
* KVMPPC_XICS_NR_IRQS.
*/
#define KVMPPC_XIVE_FIRST_IRQ 0
#define KVMPPC_XIVE_NR_IRQS KVMPPC_XICS_NR_IRQS

/*
* State for one guest irq source.
*
Expand Down Expand Up @@ -258,6 +265,9 @@ extern int (*__xive_vm_h_eoi)(struct kvm_vcpu *vcpu, unsigned long xirr);
*/
void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu);
int kvmppc_xive_debug_show_queues(struct seq_file *m, struct kvm_vcpu *vcpu);
struct kvmppc_xive_src_block *kvmppc_xive_create_src_block(
struct kvmppc_xive *xive, int irq);
void kvmppc_xive_free_sources(struct kvmppc_xive_src_block *sb);

#endif /* CONFIG_KVM_XICS */
#endif /* _KVM_PPC_BOOK3S_XICS_H */
106 changes: 106 additions & 0 deletions arch/powerpc/kvm/book3s_xive_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@

#include "book3s_xive.h"

static u8 xive_vm_esb_load(struct xive_irq_data *xd, u32 offset)
{
u64 val;

if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG)
offset |= offset << 4;

val = in_be64(xd->eoi_mmio + offset);
return (u8)val;
}

static void kvmppc_xive_native_cleanup_queue(struct kvm_vcpu *vcpu, int prio)
{
struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
Expand Down Expand Up @@ -154,12 +165,94 @@ int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
return rc;
}

static int kvmppc_xive_native_set_source(struct kvmppc_xive *xive, long irq,
u64 addr)
{
struct kvmppc_xive_src_block *sb;
struct kvmppc_xive_irq_state *state;
u64 __user *ubufp = (u64 __user *) addr;
u64 val;
u16 idx;
int rc;

pr_devel("%s irq=0x%lx\n", __func__, irq);

if (irq < KVMPPC_XIVE_FIRST_IRQ || irq >= KVMPPC_XIVE_NR_IRQS)
return -E2BIG;

sb = kvmppc_xive_find_source(xive, irq, &idx);
if (!sb) {
pr_debug("No source, creating source block...\n");
sb = kvmppc_xive_create_src_block(xive, irq);
if (!sb) {
pr_err("Failed to create block...\n");
return -ENOMEM;
}
}
state = &sb->irq_state[idx];

if (get_user(val, ubufp)) {
pr_err("fault getting user info !\n");
return -EFAULT;
}

arch_spin_lock(&sb->lock);

/*
* If the source doesn't already have an IPI, allocate
* one and get the corresponding data
*/
if (!state->ipi_number) {
state->ipi_number = xive_native_alloc_irq();
if (state->ipi_number == 0) {
pr_err("Failed to allocate IRQ !\n");
rc = -ENXIO;
goto unlock;
}
xive_native_populate_irq_data(state->ipi_number,
&state->ipi_data);
pr_debug("%s allocated hw_irq=0x%x for irq=0x%lx\n", __func__,
state->ipi_number, irq);
}

/* Restore LSI state */
if (val & KVM_XIVE_LEVEL_SENSITIVE) {
state->lsi = true;
if (val & KVM_XIVE_LEVEL_ASSERTED)
state->asserted = true;
pr_devel(" LSI ! Asserted=%d\n", state->asserted);
}

/* Mask IRQ to start with */
state->act_server = 0;
state->act_priority = MASKED;
xive_vm_esb_load(&state->ipi_data, XIVE_ESB_SET_PQ_01);
xive_native_configure_irq(state->ipi_number, 0, MASKED, 0);

/* Increment the number of valid sources and mark this one valid */
if (!state->valid)
xive->src_count++;
state->valid = true;

rc = 0;

unlock:
arch_spin_unlock(&sb->lock);

return rc;
}

static int kvmppc_xive_native_set_attr(struct kvm_device *dev,
struct kvm_device_attr *attr)
{
struct kvmppc_xive *xive = dev->private;

switch (attr->group) {
case KVM_DEV_XIVE_GRP_CTRL:
break;
case KVM_DEV_XIVE_GRP_SOURCE:
return kvmppc_xive_native_set_source(xive, attr->attr,
attr->addr);
}
return -ENXIO;
}
Expand All @@ -176,6 +269,11 @@ static int kvmppc_xive_native_has_attr(struct kvm_device *dev,
switch (attr->group) {
case KVM_DEV_XIVE_GRP_CTRL:
break;
case KVM_DEV_XIVE_GRP_SOURCE:
if (attr->attr >= KVMPPC_XIVE_FIRST_IRQ &&
attr->attr < KVMPPC_XIVE_NR_IRQS)
return 0;
break;
}
return -ENXIO;
}
Expand All @@ -184,6 +282,7 @@ static void kvmppc_xive_native_free(struct kvm_device *dev)
{
struct kvmppc_xive *xive = dev->private;
struct kvm *kvm = xive->kvm;
int i;

debugfs_remove(xive->dentry);

Expand All @@ -192,6 +291,13 @@ static void kvmppc_xive_native_free(struct kvm_device *dev)
if (kvm)
kvm->arch.xive = NULL;

for (i = 0; i <= xive->max_sbid; i++) {
if (xive->src_blocks[i])
kvmppc_xive_free_sources(xive->src_blocks[i]);
kfree(xive->src_blocks[i]);
xive->src_blocks[i] = NULL;
}

if (xive->vp_base != XIVE_INVALID_VP)
xive_native_free_vp_block(xive->vp_base);

Expand Down

0 comments on commit 4131f83

Please sign in to comment.