Commit eacc56bb authored by Cédric Le Goater's avatar Cédric Le Goater Committed by Paul Mackerras
Browse files

KVM: PPC: Book3S HV: XIVE: Introduce a new capability KVM_CAP_PPC_IRQ_XIVE



The user interface exposes a new capability KVM_CAP_PPC_IRQ_XIVE to
let QEMU connect the vCPU presenters to the XIVE KVM device if
required. The capability is not advertised for now as the full support
for the XIVE native exploitation mode is not yet available. When this
is case, the capability will be advertised on PowerNV Hypervisors
only. Nested guests (pseries KVM Hypervisor) are not supported.

Internally, the interface to the new KVM device is protected with a
new interrupt mode: KVMPPC_IRQ_XIVE.

Signed-off-by: default avatarCédric Le Goater <clg@kaod.org>
Reviewed-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
parent 90c73795
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -4504,6 +4504,15 @@ struct kvm_sync_regs {
        struct kvm_vcpu_events events;
};

6.75 KVM_CAP_PPC_IRQ_XIVE

Architectures: ppc
Target: vcpu
Parameters: args[0] is the XIVE device fd
            args[1] is the XIVE CPU number (server ID) for this vcpu

This capability connects the vcpu to an in-kernel XIVE device.

7. Capabilities that can be enabled on VMs
------------------------------------------

+1 −0
Original line number Diff line number Diff line
@@ -453,6 +453,7 @@ struct kvmppc_passthru_irqmap {
#define KVMPPC_IRQ_DEFAULT	0
#define KVMPPC_IRQ_MPIC		1
#define KVMPPC_IRQ_XICS		2 /* Includes a XIVE option */
#define KVMPPC_IRQ_XIVE		3 /* XIVE native exploitation mode */

#define MMIO_HPTE_CACHE_SIZE	4

+13 −0
Original line number Diff line number Diff line
@@ -594,6 +594,14 @@ extern int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
			       int level, bool line_status);
extern void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu);

static inline int kvmppc_xive_enabled(struct kvm_vcpu *vcpu)
{
	return vcpu->arch.irq_type == KVMPPC_IRQ_XIVE;
}

extern int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
					   struct kvm_vcpu *vcpu, u32 cpu);
extern void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu);
extern void kvmppc_xive_native_init_module(void);
extern void kvmppc_xive_native_exit_module(void);

@@ -621,6 +629,11 @@ static inline int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 ir
				      int level, bool line_status) { return -ENODEV; }
static inline void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu) { }

static inline int kvmppc_xive_enabled(struct kvm_vcpu *vcpu)
	{ return 0; }
static inline int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
			  struct kvm_vcpu *vcpu, u32 cpu) { return -EBUSY; }
static inline void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu) { }
static inline void kvmppc_xive_native_init_module(void) { }
static inline void kvmppc_xive_native_exit_module(void) { }

+47 −41
Original line number Diff line number Diff line
@@ -380,11 +380,6 @@ static int xive_select_target(struct kvm *kvm, u32 *server, u8 prio)
	return -EBUSY;
}

static u32 xive_vp(struct kvmppc_xive *xive, u32 server)
{
	return xive->vp_base + kvmppc_pack_vcpu_id(xive->kvm, server);
}

static u8 xive_lock_and_mask(struct kvmppc_xive *xive,
			     struct kvmppc_xive_src_block *sb,
			     struct kvmppc_xive_irq_state *state)
@@ -430,7 +425,7 @@ static u8 xive_lock_and_mask(struct kvmppc_xive *xive,
	 */
	if (xd->flags & OPAL_XIVE_IRQ_MASK_VIA_FW) {
		xive_native_configure_irq(hw_num,
					  xive_vp(xive, state->act_server),
				kvmppc_xive_vp(xive, state->act_server),
				MASKED, state->number);
		/* set old_p so we can track if an H_EOI was done */
		state->old_p = true;
@@ -486,7 +481,7 @@ static void xive_finish_unmask(struct kvmppc_xive *xive,
	 */
	if (xd->flags & OPAL_XIVE_IRQ_MASK_VIA_FW) {
		xive_native_configure_irq(hw_num,
					  xive_vp(xive, state->act_server),
				kvmppc_xive_vp(xive, state->act_server),
				state->act_priority, state->number);
		/* If an EOI is needed, do it here */
		if (!state->old_p)
@@ -563,7 +558,7 @@ static int xive_target_interrupt(struct kvm *kvm,
	kvmppc_xive_select_irq(state, &hw_num, NULL);

	return xive_native_configure_irq(hw_num,
					 xive_vp(xive, server),
					 kvmppc_xive_vp(xive, server),
					 prio, state->number);
}

@@ -951,7 +946,7 @@ int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq,
	 * which is fine for a never started interrupt.
	 */
	xive_native_configure_irq(hw_irq,
				  xive_vp(xive, state->act_server),
				  kvmppc_xive_vp(xive, state->act_server),
				  state->act_priority, state->number);

	/*
@@ -1027,7 +1022,7 @@ int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,

	/* Reconfigure the IPI */
	xive_native_configure_irq(state->ipi_number,
				  xive_vp(xive, state->act_server),
				  kvmppc_xive_vp(xive, state->act_server),
				  state->act_priority, state->number);

	/*
@@ -1049,7 +1044,7 @@ int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,
}
EXPORT_SYMBOL_GPL(kvmppc_xive_clr_mapped);

static void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu)
void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu)
{
	struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
	struct kvm *kvm = vcpu->kvm;
@@ -1166,7 +1161,7 @@ int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
	xc->xive = xive;
	xc->vcpu = vcpu;
	xc->server_num = cpu;
	xc->vp_id = xive_vp(xive, cpu);
	xc->vp_id = kvmppc_xive_vp(xive, cpu);
	xc->mfrr = 0xff;
	xc->valid = true;

@@ -1883,6 +1878,43 @@ static int kvmppc_xive_create(struct kvm_device *dev, u32 type)
	return 0;
}

int kvmppc_xive_debug_show_queues(struct seq_file *m, struct kvm_vcpu *vcpu)
{
	struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
	unsigned int i;

	for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
		struct xive_q *q = &xc->queues[i];
		u32 i0, i1, idx;

		if (!q->qpage && !xc->esc_virq[i])
			continue;

		seq_printf(m, " [q%d]: ", i);

		if (q->qpage) {
			idx = q->idx;
			i0 = be32_to_cpup(q->qpage + idx);
			idx = (idx + 1) & q->msk;
			i1 = be32_to_cpup(q->qpage + idx);
			seq_printf(m, "T=%d %08x %08x...\n", q->toggle,
				   i0, i1);
		}
		if (xc->esc_virq[i]) {
			struct irq_data *d = irq_get_irq_data(xc->esc_virq[i]);
			struct xive_irq_data *xd =
				irq_data_get_irq_handler_data(d);
			u64 pq = xive_vm_esb_load(xd, XIVE_ESB_GET);

			seq_printf(m, "E:%c%c I(%d:%llx:%llx)",
				   (pq & XIVE_ESB_VAL_P) ? 'P' : 'p',
				   (pq & XIVE_ESB_VAL_Q) ? 'Q' : 'q',
				   xc->esc_virq[i], pq, xd->eoi_page);
			seq_puts(m, "\n");
		}
	}
	return 0;
}

static int xive_debug_show(struct seq_file *m, void *private)
{
@@ -1908,7 +1940,6 @@ static int xive_debug_show(struct seq_file *m, void *private)

	kvm_for_each_vcpu(i, vcpu, kvm) {
		struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
		unsigned int i;

		if (!xc)
			continue;
@@ -1918,33 +1949,8 @@ static int xive_debug_show(struct seq_file *m, void *private)
			   xc->server_num, xc->cppr, xc->hw_cppr,
			   xc->mfrr, xc->pending,
			   xc->stat_rm_h_xirr, xc->stat_vm_h_xirr);
		for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
			struct xive_q *q = &xc->queues[i];
			u32 i0, i1, idx;

			if (!q->qpage && !xc->esc_virq[i])
				continue;

			seq_printf(m, " [q%d]: ", i);

			if (q->qpage) {
				idx = q->idx;
				i0 = be32_to_cpup(q->qpage + idx);
				idx = (idx + 1) & q->msk;
				i1 = be32_to_cpup(q->qpage + idx);
				seq_printf(m, "T=%d %08x %08x... \n", q->toggle, i0, i1);
			}
			if (xc->esc_virq[i]) {
				struct irq_data *d = irq_get_irq_data(xc->esc_virq[i]);
				struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
				u64 pq = xive_vm_esb_load(xd, XIVE_ESB_GET);
				seq_printf(m, "E:%c%c I(%d:%llx:%llx)",
					   (pq & XIVE_ESB_VAL_P) ? 'P' : 'p',
					   (pq & XIVE_ESB_VAL_Q) ? 'Q' : 'q',
					   xc->esc_virq[i], pq, xd->eoi_page);
				seq_printf(m, "\n");
			}
		}
		kvmppc_xive_debug_show_queues(m, vcpu);

		t_rm_h_xirr += xc->stat_rm_h_xirr;
		t_rm_h_ipoll += xc->stat_rm_h_ipoll;
+11 −0
Original line number Diff line number Diff line
@@ -198,6 +198,11 @@ static inline struct kvmppc_xive_src_block *kvmppc_xive_find_source(struct kvmpp
	return xive->src_blocks[bid];
}

static inline u32 kvmppc_xive_vp(struct kvmppc_xive *xive, u32 server)
{
	return xive->vp_base + kvmppc_pack_vcpu_id(xive->kvm, server);
}

/*
 * Mapping between guest priorities and host priorities
 * is as follow.
@@ -248,5 +253,11 @@ extern int (*__xive_vm_h_ipi)(struct kvm_vcpu *vcpu, unsigned long server,
extern int (*__xive_vm_h_cppr)(struct kvm_vcpu *vcpu, unsigned long cppr);
extern int (*__xive_vm_h_eoi)(struct kvm_vcpu *vcpu, unsigned long xirr);

/*
 * Common Xive routines for XICS-over-XIVE and XIVE native
 */
void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu);
int kvmppc_xive_debug_show_queues(struct seq_file *m, struct kvm_vcpu *vcpu);

#endif /* CONFIG_KVM_XICS */
#endif /* _KVM_PPC_BOOK3S_XICS_H */
Loading