kvmarm.lists.cs.columbia.edu archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller
@ 2020-09-03 15:25 Marc Zyngier
  2020-09-03 15:25 ` [PATCH 01/23] irqchip: Add Reduced Virtual Interrupt Controller driver Marc Zyngier
                   ` (22 more replies)
  0 siblings, 23 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Anyone vaguely familiar with the ARM interrupt architecture (also
known as GIC) would certainly agree that it isn't the simplest thing
to deal with. Its features are ranging from simple, bare metal
interrupt delivery to full blown direct injection into a guest.

It is also horribly complex, full of backward[-compatibility]
features, and it is very hard to reason about what is going on in the
system at any given time. For a hypervisor such as KVM, the GIC is an
invasive beast that accounts for a large part of the privileged
software we run, as it implements the whole of the architecture with
bells and whistles as it tries to cater for all possible guests.

At the same time, we have an ongoing effort to make KVM/arm64 a more
"verifiable" hypervisor, by allowing only a small amount of code to
run at EL2. Moving most of the GIC emulation to userspace would
involve sacrificing performance (the architecture really doesn't lend
itself to a split model, despite the appearances), and proving that it
is actually completely safe is almost an impossible task (I have seen
people trying!).

Another approach is to bite the bullet, and design from the ground up
an interrupt controller that:

- works well enough for workloads that mostly deal with virtual
  interrupts (no device assignment),

- is as simple as possible for the hypervisor to implement.

Since we cannot retrospectively hack the HW, this is a paravirtualized
interrupt controller, where every single operation results in a trap.
Yes, it looks like it would be terribly expensive. Or not.

The result of the above is a specification from ARM [1] that defines
the RVIC and RVID components that make the interrupt controller. It is
an *Alpha* spec, to it is very much subject to changes (the hypercall
numbers have been redacted out to make that explicit).

The result of the above result is this patch series, which provides
Linux drivers for rVIC and rVID, as well as a KVM implementation that
can be exposed to guests. Most of the patches are a big refactor of
the KVM/arm64 code to allow a non-GIC irqchip to be exposed to the
guest, as the code that actually deals with delivering interrupts is
pretty simple. I intend to carry on refactoring this as more
structures could be made irqchip agnostic.

We have:

- Support for the rVIC/rVID PV interrupt controller architecture in a
  guest

- A large rework of the way the vgic integrates with the rest of KVM,
  mostly punching a vgic-shaped hole in the code, and replacing it with
  a set of optional callbacks that an interrupt controller
  implementation can provide, or not.

- A rVIC/rVID implementation for KVM/arm64.

This is based on my previously posted IPI-as-IRQ series

How does it fare? Well, it's not even bad. There is a bit more
overhead than with an actual GIC, but you need to squint really hard
to see a difference. Turns out that interacting with a HW interrupt
controller isn't free either... Of course, YMMV, and I'd happily look
at performance figures if someone has the guts to put them together.

What is missing:

- Patches for userspace to actually start a rVIC-equipped guest. I
  have pushed a kvmtool branch at [2]. This is just a terrible pile of
  hacks, don't trust it to do anything right. It works well enough to
  spawn a guest with virtio-pci and deliver MSIs though.

- DT bindings, which I need to write up

- ACPI? Why not...

Things that are *not* in the spec:

- MSIs. I've made them up in the driver and KVM, and I don't think we
  can do without them. I intend to feed that requirement back to ARM.

- RVID level interrupts. We need them to implement PCI INTx.

- Priorities. Not clear whether we really need those, and it would
  certainly complixify the design.

This has been lightly tested on a A55-based system running VHE, and
equipped with a GICv2, as well as a couple of nVHE systems with both
GICv2 and GICv3. VHE+GICv3 is still untested, as I lack the platform
(someone please send me an Ampere Altra box ;-).

Patches are based on v5.9-rc3 + the IPI patches, and a branch with
everything stacked together is at [3].

[1] https://developer.arm.com/architectures/system-architectures/software-standards/rvic
[2] https://git.kernel.org/pub/scm/linux/kernel/git/maz/kvmtool.git/log/?h=rvic
[3] https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=irq/rvic

Marc Zyngier (23):
  irqchip: Add Reduced Virtual Interrupt Controller driver
  irqchip/rvic: Add support for untrusted interrupt allocation
  irqchip: Add Reduced Virtual Interrupt Distributor support
  irqchip/rvid: Add PCI MSI support
  KVM: arm64: Move GIC model out of the distributor
  KVM: arm64: vgic-v3: Move early init to kvm_vgic_create()
  KVM: arm64: Add irqchip callback structure to kvm_arch
  KVM: arm64: Move kvm_vgic_destroy to kvm_irqchip_flow
  KVM: arm64: Move kvm_vgic_vcpu_init() to irqchip_flow
  KVM: arm64: Move kvm_vgic_vcpu_[un]blocking() to irqchip_flow
  KVM: arm64: Move kvm_vgic_vcpu_load/put() to irqchip_flow
  KVM: arm64: Move kvm_vgic_vcpu_pending_irq() to irqchip_flow
  KVM: arm64: Move vgic resource mapping on first run to irqchip_flow
  KVM: arm64: Move kvm_vgic_vcpu_{sync,flush}_hwstate() to irqchip_flow
  KVM: arm64: nVHE: Only save/restore GICv3 state if modeling a GIC
  KVM: arm64: Move interrupt injection to irqchip_flow
  KVM: arm64: Move mapping of HW interrupts into irqchip_flow
  KVM: arm64: Move set_owner into irqchip_flow
  KVM: arm64: Turn vgic_initialized into irqchip_finalized
  KVM: arm64: Move irqfd routing to irqchip_flow
  KVM: arm64: Tighten msis_require_devid reporting
  KVM: arm64: Add a rVIC/rVID in-kernel implementation
  KVM: arm64: Add debugfs files for the rVIC/rVID implementation

 arch/arm64/include/asm/kvm_host.h     |   11 +-
 arch/arm64/include/asm/kvm_irq.h      |  136 +++
 arch/arm64/include/uapi/asm/kvm.h     |    9 +
 arch/arm64/kvm/Makefile               |    2 +-
 arch/arm64/kvm/arch_timer.c           |   36 +-
 arch/arm64/kvm/arm.c                  |  141 ++-
 arch/arm64/kvm/hyp/nvhe/switch.c      |   12 +-
 arch/arm64/kvm/hypercalls.c           |    7 +
 arch/arm64/kvm/pmu-emul.c             |   10 +-
 arch/arm64/kvm/rvic-cpu.c             | 1213 +++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic-debug.c      |    7 +-
 arch/arm64/kvm/vgic/vgic-init.c       |  133 ++-
 arch/arm64/kvm/vgic/vgic-irqfd.c      |   72 +-
 arch/arm64/kvm/vgic/vgic-its.c        |    2 +-
 arch/arm64/kvm/vgic/vgic-kvm-device.c |   18 +-
 arch/arm64/kvm/vgic/vgic-mmio-v3.c    |    2 +-
 arch/arm64/kvm/vgic/vgic-mmio.c       |   10 +-
 arch/arm64/kvm/vgic/vgic-v2.c         |    5 -
 arch/arm64/kvm/vgic/vgic-v3.c         |   26 +-
 arch/arm64/kvm/vgic/vgic.c            |   55 +-
 arch/arm64/kvm/vgic/vgic.h            |   37 +
 drivers/irqchip/Kconfig               |   12 +
 drivers/irqchip/Makefile              |    2 +
 drivers/irqchip/irq-rvic.c            |  595 ++++++++++++
 drivers/irqchip/irq-rvid.c            |  441 +++++++++
 include/kvm/arm_rvic.h                |   41 +
 include/kvm/arm_vgic.h                |   33 -
 include/linux/cpuhotplug.h            |    1 +
 include/linux/irqchip/irq-rvic.h      |  100 ++
 include/uapi/linux/kvm.h              |    2 +
 30 files changed, 2907 insertions(+), 264 deletions(-)
 create mode 100644 arch/arm64/include/asm/kvm_irq.h
 create mode 100644 arch/arm64/kvm/rvic-cpu.c
 create mode 100644 drivers/irqchip/irq-rvic.c
 create mode 100644 drivers/irqchip/irq-rvid.c
 create mode 100644 include/kvm/arm_rvic.h
 create mode 100644 include/linux/irqchip/irq-rvic.h

-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 01/23] irqchip: Add Reduced Virtual Interrupt Controller driver
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-03 15:25 ` [PATCH 02/23] irqchip/rvic: Add support for untrusted interrupt allocation Marc Zyngier
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

The ARM rVIC is the simplest PV interrupt controller on this side
of the universe. I mean it!

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 drivers/irqchip/Kconfig          |   6 +
 drivers/irqchip/Makefile         |   1 +
 drivers/irqchip/irq-rvic.c       | 554 +++++++++++++++++++++++++++++++
 include/linux/cpuhotplug.h       |   1 +
 include/linux/irqchip/irq-rvic.h |  77 +++++
 5 files changed, 639 insertions(+)
 create mode 100644 drivers/irqchip/irq-rvic.c
 create mode 100644 include/linux/irqchip/irq-rvic.h

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index bfc9719dbcdc..348ff1d06651 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -61,6 +61,12 @@ config ARM_NVIC
 	select IRQ_DOMAIN_HIERARCHY
 	select GENERIC_IRQ_CHIP
 
+config ARM_RVIC
+	bool
+	default ARM64
+	select IRQ_DOMAIN_HIERARCHY
+	select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+
 config ARM_VIC
 	bool
 	select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 133f9c45744a..d2b280efd2e0 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC)	+= irq-gic-v3-its-fsl-mc-msi.o
 obj-$(CONFIG_PARTITION_PERCPU)		+= irq-partition-percpu.o
 obj-$(CONFIG_HISILICON_IRQ_MBIGEN)	+= irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
+obj-$(CONFIG_ARM_RVIC)			+= irq-rvic.o
 obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
 obj-$(CONFIG_ARMADA_370_XP_IRQ)		+= irq-armada-370-xp.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-rvic.c b/drivers/irqchip/irq-rvic.c
new file mode 100644
index 000000000000..6f37aa4318b6
--- /dev/null
+++ b/drivers/irqchip/irq-rvic.c
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A Reduced Virtual Interrupt Controler driver
+ *
+ * Initial draft from Alex Shirshikov <alexander.shirshikov@arm.com>
+ *
+ * Copyright 2020 Google LLC.
+ * Author: Marc Zyngier <maz@kernel.org>
+ */
+
+
+#define pr_fmt(fmt)	"rVIC: " fmt
+
+#include <linux/arm-smccc.h>
+#include <linux/cpuhotplug.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+
+#include <linux/irqchip/irq-rvic.h>
+
+#include <asm/exception.h>
+
+#define RVIC_WARN_INTID_TARGET(r, s, intid, mpid)			\
+	WARN((r), "Error " s " INTID%ld target %llx (%ld, %ld)\n", \
+	     (intid), (mpid),						\
+	     RVIC_STATUS_REASON((r)), RVIC_STATUS_INDEX((r)));
+
+#define RVIC_WARN_INTID(r, s, intid)					\
+	WARN((r), "Error " s " INTID%ld (%ld, %ld)\n",	\
+	     (intid),							\
+	     RVIC_STATUS_REASON((r)), RVIC_STATUS_INDEX((r)));
+
+static DEFINE_PER_CPU(unsigned long *, trusted_masked);
+
+struct rvic_data {
+	struct fwnode_handle	*fwnode;
+	struct irq_domain	*domain;
+	unsigned int		nr_trusted;
+	unsigned int		nr_untrusted;
+};
+
+static struct rvic_data rvic;
+
+static inline int rvic_version(unsigned long *version)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_VERSION, &res);
+	if (res.a0 == RVIC_STATUS_SUCCESS)
+		*version = res.a1;
+	return res.a0;
+}
+
+static inline unsigned long rvic_info(unsigned long key,
+				      unsigned long *value)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_INFO, key, &res);
+	if (res.a0 == RVIC_STATUS_SUCCESS)
+		*value = res.a1;
+	return res.a0;
+}
+
+static inline unsigned long rvic_enable(void)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_ENABLE, &res);
+	return res.a0;
+}
+
+static inline unsigned long rvic_disable(void)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_DISABLE, &res);
+	return res.a0;
+}
+
+static inline unsigned long rvic_set_masked(unsigned long target,
+					    unsigned long intid)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_SET_MASKED, target, intid, &res);
+	return res.a0;
+}
+
+static inline unsigned long rvic_clear_masked(unsigned long target,
+					      unsigned long intid)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_CLEAR_MASKED, target, intid, &res);
+	return res.a0;
+}
+
+static inline unsigned long rvic_is_pending(unsigned long target,
+					    unsigned long intid,
+					    bool *is_pending)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_IS_PENDING, target, intid, &res);
+	if (res.a0 == RVIC_STATUS_SUCCESS)
+		*is_pending = res.a1;
+	return res.a0;
+}
+
+static inline unsigned long rvic_signal(unsigned long target,
+					unsigned long intid)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_SIGNAL, target, intid, &res);
+	return res.a0;
+}
+
+static inline unsigned long rvic_clear_pending(unsigned long target,
+					       unsigned long intid)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_CLEAR_PENDING, target, intid, &res);
+	return res.a0;
+}
+
+static inline unsigned long rvic_acknowledge(unsigned long *intid)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_ACKNOWLEDGE, &res);
+	if (res.a0 == RVIC_STATUS_SUCCESS)
+		*intid = res.a1;
+	return res.a0;
+}
+
+static inline unsigned long rvic_resample(unsigned long intid)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVIC_RESAMPLE, intid, &res);
+	return res.a0;
+}
+
+static u64 rvic_irq_to_mpidr(struct irq_data *data, int *cpup)
+{
+	int cpu;
+
+	if (data->hwirq < rvic.nr_trusted) {
+		*cpup = smp_processor_id();
+		return read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
+	}
+
+	cpu = cpumask_first(data->common->effective_affinity);
+	*cpup = cpu;
+	return cpu_logical_map(cpu) & MPIDR_HWID_BITMASK;
+}
+
+static void rvic_irq_mask(struct irq_data *data)
+{
+	unsigned long ret;
+	u64 mpidr;
+	int cpu;
+
+	mpidr = rvic_irq_to_mpidr(data, &cpu);
+	pr_debug("%llu irq %d hwirq %ld masked\n",
+		 mpidr, data->irq, data->hwirq);
+	ret = rvic_set_masked(mpidr, data->hwirq);
+	RVIC_WARN_INTID_TARGET(ret, "masking", data->hwirq, mpidr);
+
+	if (data->hwirq < rvic.nr_trusted)
+		set_bit(data->hwirq, per_cpu(trusted_masked, cpu));
+}
+
+static void rvic_irq_unmask(struct irq_data *data)
+{
+	unsigned long ret;
+	u64 mpidr;
+	int cpu;
+
+	mpidr = rvic_irq_to_mpidr(data, &cpu);
+	pr_debug("%llu irq %d hwirq %ld unmasked\n",
+		 mpidr, data->irq, data->hwirq);
+	ret = rvic_clear_masked(mpidr, data->hwirq);
+	RVIC_WARN_INTID_TARGET(ret, "unmasking", data->hwirq, mpidr);
+
+	if (data->hwirq < rvic.nr_trusted)
+		clear_bit(data->hwirq, per_cpu(trusted_masked, cpu));
+}
+
+static void rvic_irq_eoi(struct irq_data *data)
+{
+	bool masked;
+
+	/* Resampling is only available on trusted interrupts for now */
+	if (data->hwirq < rvic.nr_trusted &&
+	    (irqd_get_trigger_type(data) & IRQ_TYPE_LEVEL_MASK)) {
+		unsigned long ret;
+
+		ret = rvic_resample(data->hwirq);
+		RVIC_WARN_INTID(ret, "resampling", data->hwirq);
+	}
+
+	/* irqd_irq_masked doesn't work on percpu-devid interrupts. */
+	if (data->hwirq < rvic.nr_trusted)
+		masked = test_bit(data->hwirq, *this_cpu_ptr(&trusted_masked));
+	else
+		masked = irqd_irq_masked(data);
+
+	if (!masked)
+		rvic_irq_unmask(data);
+}
+
+static void rvic_ipi_send_mask(struct irq_data *data,
+			       const struct cpumask *mask)
+{
+	int cpu;
+
+	for_each_cpu(cpu, mask) {
+		u64 mpidr = cpu_logical_map(cpu) & MPIDR_HWID_BITMASK;
+		unsigned long ret;
+
+		ret = rvic_signal(mpidr, data->hwirq);
+		RVIC_WARN_INTID_TARGET(ret, "signaling", data->hwirq, mpidr);
+	}
+}
+
+static int rvic_irq_get_irqchip_state(struct irq_data *data,
+				      enum irqchip_irq_state which, bool *val)
+{
+	unsigned long ret;
+	u64 mpidr;
+	int cpu;
+
+	mpidr = rvic_irq_to_mpidr(data, &cpu);
+
+	switch (which) {
+	case IRQCHIP_STATE_PENDING:
+		ret = rvic_is_pending(mpidr, data->hwirq, val);
+		RVIC_WARN_INTID_TARGET(ret, "getting pending state",
+				       data->hwirq, mpidr);
+		return ret ? -EINVAL : 0;
+
+	default:
+		return -EINVAL;
+	};
+}
+
+static int rvic_irq_set_irqchip_state(struct irq_data *data,
+				      enum irqchip_irq_state which, bool val)
+{
+	unsigned long ret;
+	u64 mpidr;
+	int cpu;
+
+	mpidr = rvic_irq_to_mpidr(data, &cpu);
+
+	switch (which) {
+	case IRQCHIP_STATE_PENDING:
+		if (val)
+			ret = rvic_signal(mpidr, data->hwirq);
+		else
+			ret = rvic_clear_pending(mpidr, data->hwirq);
+		RVIC_WARN_INTID_TARGET(ret, "setting pending state",
+				       data->hwirq, mpidr);
+		return ret ? -EINVAL : 0;
+
+	case IRQCHIP_STATE_MASKED:
+		if (val)
+			ret = rvic_set_masked(mpidr, data->hwirq);
+		else
+			ret = rvic_clear_masked(mpidr, data->hwirq);
+		RVIC_WARN_INTID_TARGET(ret, "setting masked state",
+				       data->hwirq, mpidr);
+		return ret ? -EINVAL : 0;
+
+	default:
+		return -EINVAL;
+	}
+
+}
+
+static int rvic_irq_retrigger(struct irq_data *data)
+{
+	return !!rvic_irq_set_irqchip_state(data, IRQCHIP_STATE_PENDING, true);
+}
+
+static int rvic_set_type(struct irq_data *data, unsigned int type)
+{
+	/*
+	 * Nothing to do here, we're always edge under the hood. Just
+	 * weed out untrusted interrupts, as they cannot be level yet.
+	 */
+	switch (type) {
+	case IRQ_TYPE_LEVEL_HIGH:
+		if (data->hwirq >= rvic.nr_trusted)
+			return -EINVAL;
+
+		fallthrough;
+	case IRQ_TYPE_EDGE_RISING:
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct irq_chip rvic_chip = {
+	.name			= "rvic",
+	.irq_mask		= rvic_irq_mask,
+	.irq_unmask		= rvic_irq_unmask,
+	.irq_eoi		= rvic_irq_eoi,
+	.ipi_send_mask		= rvic_ipi_send_mask,
+	.irq_get_irqchip_state	= rvic_irq_get_irqchip_state,
+	.irq_set_irqchip_state	= rvic_irq_set_irqchip_state,
+	.irq_retrigger		= rvic_irq_retrigger,
+	.irq_set_type		= rvic_set_type,
+};
+
+static asmlinkage void __exception_irq_entry rvic_handle_irq(struct pt_regs *regs)
+{
+	unsigned long ret, intid;
+	int err;
+
+	ret = rvic_acknowledge(&intid);
+	if (unlikely(ret == RVIC_STATUS_NO_INTERRUPTS)) {
+		pr_debug("CPU%d: Spurious interrupt\n", smp_processor_id());
+		return;
+	}
+
+	if ((unlikely(ret))) {
+		WARN(1, "rVIC: Error acknowledging interrupt (%ld, %ld)\n",
+		     RVIC_STATUS_REASON(ret),
+		     RVIC_STATUS_INDEX(ret));
+		return;
+	}
+
+	if (unlikely(intid >= (rvic.nr_trusted + rvic.nr_untrusted))) {
+		WARN(1, "Unexpected intid out of range (%lu)\n", intid);
+		return;
+	}
+
+	pr_debug("CPU%d: IRQ%ld\n", smp_processor_id(), intid);
+	err = handle_domain_irq(rvic.domain, intid, regs);
+	WARN_ONCE(err, "Unexpected interrupt received %d\n", err);
+}
+
+static int rvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+				 unsigned int nr_irqs, void *arg)
+{
+	struct irq_fwspec *fwspec = arg;
+	unsigned int type = IRQ_TYPE_NONE;
+	irq_hw_number_t hwirq;
+	int i, ret;
+
+	ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < nr_irqs; i++) {
+		unsigned int intid = hwirq + i;
+		unsigned int irq = virq + i;
+
+		if (intid < 16) {
+			irq_set_percpu_devid(irq);
+			irq_domain_set_info(domain, irq, intid, &rvic_chip,
+					    domain->host_data,
+					    handle_percpu_devid_fasteoi_ipi,
+					    NULL, NULL);
+		} else if (intid < rvic.nr_trusted) {
+			irq_set_percpu_devid(irq);
+			irq_domain_set_info(domain, irq, intid, &rvic_chip,
+					    domain->host_data,
+					    handle_percpu_devid_irq,
+					    NULL, NULL);
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static void rvic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
+				 unsigned int nr_irqs)
+{
+	int i;
+
+	for (i = 0; i < nr_irqs; i++) {
+		struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
+		irq_set_handler(virq + i, NULL);
+		irq_domain_reset_irq_data(d);
+	}
+}
+
+static const struct irq_domain_ops rvic_irq_domain_ops = {
+	.translate	= irq_domain_translate_twocell,
+	.alloc		= rvic_irq_domain_alloc,
+	.free		= rvic_irq_domain_free,
+};
+
+static int rvic_cpu_starting(unsigned int cpu)
+{
+	u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
+	unsigned long ret;
+	int i;
+
+	rvic_disable();
+
+	for (i = 0; i < (rvic.nr_trusted + rvic.nr_untrusted); i++) {
+		rvic_set_masked(mpidr, i);
+		rvic_clear_pending(mpidr, i);
+	}
+
+	ret = rvic_enable();
+	if (ret != RVIC_STATUS_SUCCESS) {
+		pr_err("rVIC: error enabling instance (%ld, %ld)\n",
+		       RVIC_STATUS_REASON(ret),
+		       RVIC_STATUS_INDEX(ret));
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int rvic_cpu_dying(unsigned int cpu)
+{
+	unsigned long ret;
+
+	ret = rvic_disable();
+	if (ret != RVIC_STATUS_SUCCESS) {
+		pr_err("rVIC: error disabling instance (%ld, %ld)\n",
+		       RVIC_STATUS_REASON(ret),
+		       RVIC_STATUS_INDEX(ret));
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void __init rvic_smp_init(struct fwnode_handle *fwnode)
+{
+	struct irq_fwspec ipi_fwspec = {
+		.fwnode		= fwnode,
+		.param_count	= 2,
+		.param[0]	= 0,
+		.param[1]	= IRQ_TYPE_EDGE_RISING,
+	};
+	int base_ipi;
+
+	cpuhp_setup_state(CPUHP_AP_IRQ_RVIC_STARTING, "irqchip/rvic:starting",
+			  rvic_cpu_starting, rvic_cpu_dying);
+
+	base_ipi = __irq_domain_alloc_irqs(rvic.domain, -1, 16,
+					   NUMA_NO_NODE, &ipi_fwspec,
+					   false, NULL);
+	if (WARN_ON(base_ipi < 0))
+		return;
+
+	set_smp_ipi_range(base_ipi, 16);
+}
+
+static int __init rvic_init(struct device_node *node,
+			    struct device_node *parent)
+{
+	unsigned long ret, version, val;
+	int cpu;
+
+	if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_1) {
+		pr_err("SMCCC 1.1 required, abording\n");
+		return -EINVAL;
+	}
+
+	rvic.fwnode = of_node_to_fwnode(node);
+
+	ret = rvic_version(&version);
+	if (ret != RVIC_STATUS_SUCCESS) {
+		pr_err("error retrieving version (%ld, %ld)\n",
+		       RVIC_STATUS_REASON(ret),
+		       RVIC_STATUS_INDEX(ret));
+		return -ENXIO;
+	}
+
+	if (version < RVIC_VERSION(0, 3)) {
+		pr_err("version (%ld, %ld) too old, expected min. (%d, %d)\n",
+		       RVIC_VERSION_MAJOR(version),
+		       RVIC_VERSION_MINOR(version),
+		       0, 3);
+		return -ENXIO;
+	}
+
+	ret = rvic_info(RVIC_INFO_KEY_NR_TRUSTED_INTERRUPTS, &val);
+	if (ret != RVIC_STATUS_SUCCESS) {
+		pr_err("error retrieving nr of trusted interrupts (%ld, %ld)\n",
+		       RVIC_STATUS_REASON(ret),
+		       RVIC_STATUS_INDEX(ret));
+		return -ENXIO;
+	}
+
+	rvic.nr_trusted = val;
+
+	ret = rvic_info(RVIC_INFO_KEY_NR_UNTRUSTED_INTERRUPTS, &val);
+	if (ret != RVIC_STATUS_SUCCESS) {
+		pr_err("error retrieving nr of untrusted interrupts (%ld, %ld)\n",
+		       RVIC_STATUS_REASON(ret),
+		       RVIC_STATUS_INDEX(ret));
+		return -ENXIO;
+	}
+
+	rvic.nr_untrusted = val;
+
+	pr_info("probed %u trusted interrupts, %u untrusted interrupts\n",
+		rvic.nr_trusted, rvic.nr_untrusted);
+
+	rvic.domain = irq_domain_create_linear(rvic.fwnode,
+					       rvic.nr_trusted + rvic.nr_untrusted,
+					       &rvic_irq_domain_ops, &rvic);
+	if (!rvic.domain) {
+		pr_warn("Failed to allocate irq domain\n");
+		return -ENOMEM;
+	}
+
+	for_each_possible_cpu(cpu) {
+		unsigned long *map = bitmap_alloc(rvic.nr_trusted, GFP_KERNEL);
+
+		if (!map) {
+			pr_warn("Failed to allocate trusted bitmap (CPU %d)\n",
+				cpu);
+			goto free_percpu;
+		}
+
+		/* Default to masked */
+		bitmap_fill(map, rvic.nr_trusted);
+		per_cpu(trusted_masked, cpu) = map;
+	}
+
+	rvic_smp_init(rvic.fwnode);
+	set_handle_irq(rvic_handle_irq);
+
+	return 0;
+
+free_percpu:
+	for_each_possible_cpu(cpu)
+		kfree(per_cpu(trusted_masked, cpu));
+
+	irq_domain_remove(rvic.domain);
+
+	return -ENOMEM;
+}
+
+IRQCHIP_DECLARE(rvic, "arm,rvic", rvic_init);
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 3215023d4852..ddaa57157af0 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -101,6 +101,7 @@ enum cpuhp_state {
 	CPUHP_AP_IRQ_HIP04_STARTING,
 	CPUHP_AP_IRQ_ARMADA_XP_STARTING,
 	CPUHP_AP_IRQ_BCM2836_STARTING,
+	CPUHP_AP_IRQ_RVIC_STARTING,
 	CPUHP_AP_IRQ_MIPS_GIC_STARTING,
 	CPUHP_AP_IRQ_RISCV_STARTING,
 	CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
diff --git a/include/linux/irqchip/irq-rvic.h b/include/linux/irqchip/irq-rvic.h
new file mode 100644
index 000000000000..0176ca7d3c30
--- /dev/null
+++ b/include/linux/irqchip/irq-rvic.h
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Definitions for rVIC/rVID PV interrupt controller architecture.
+ *
+ * Copyright 2020 Google LLC.
+ * Author: Marc Zyngier <maz@kernel.org>
+ *
+ * WARNING: All these constants are subject to change until the spec is final.
+ */
+
+#ifndef __IRQCHIP_IRQ_RVIC_H__
+#define __IRQCHIP_IRQ_RVIC_H__
+
+#include <linux/bitfield.h>
+
+/* Versioning */
+#define RVIx_VERSION_MAJOR_MASK		GENMASK(31, 16)
+#define RVIx_VERSION_MINOR_MASK		GENMASK(15, 0)
+
+#define RVIx_VERSION(M, m)				\
+	(FIELD_PREP(RVIx_VERSION_MAJOR_MASK, (M)) |	\
+	 FIELD_PREP(RVIx_VERSION_MINOR_MASK, (m)))
+
+#define RVIx_VERSION_MAJOR(v)		FIELD_GET(RVIx_VERSION_MAJOR_MASK, (v))
+#define RVIx_VERSION_MINOR(v)		FIELD_GET(RVIx_VERSION_MINOR_MASK, (v))
+
+/* Error reporting */
+#define RVIx_STATUS_REASON_MASK		GENMASK(7, 0)
+#define RVIx_STATUS_INDEX_MASK		GENMASK(15, 8)
+
+#define RVIx_STATUS_PACK(r,i)				\
+	(FIELD_PREP(RVIx_STATUS_REASON_MASK, (r)) |	\
+	 FIELD_PREP(RVIx_STATUS_INDEX_MASK, (i)))
+
+#define RVIx_STATUS_REASON(c)		FIELD_GET(RVIx_STATUS_REASON_MASK, (c))
+#define RVIx_STATUS_INDEX(c)		FIELD_GET(RVIx_STATUS_INDEX_MASK, (c))
+
+#define RVIx_STATUS_SUCCESS		0
+#define RVIx_STATUS_ERROR_PARAMETER	1
+#define RVIx_STATUS_INVALID_CPU		2
+#define RVIx_STATUS_DISABLED		3
+#define RVIx_STATUS_NO_INTERRUPTS	4
+
+/* rVIC functions */
+#define SMC64_RVIC_BASE			0xc5000200
+#define SMC64_RVIC_FN(n)		(SMC64_RVIC_BASE + (n))
+
+#define SMC64_RVIC_VERSION		SMC64_RVIC_FN(0)
+#define SMC64_RVIC_INFO			SMC64_RVIC_FN(1)
+#define SMC64_RVIC_ENABLE		SMC64_RVIC_FN(2)
+#define SMC64_RVIC_DISABLE		SMC64_RVIC_FN(3)
+#define SMC64_RVIC_SET_MASKED		SMC64_RVIC_FN(4)
+#define SMC64_RVIC_CLEAR_MASKED		SMC64_RVIC_FN(5)
+#define SMC64_RVIC_IS_PENDING		SMC64_RVIC_FN(6)
+#define SMC64_RVIC_SIGNAL		SMC64_RVIC_FN(7)
+#define SMC64_RVIC_CLEAR_PENDING	SMC64_RVIC_FN(8)
+#define SMC64_RVIC_ACKNOWLEDGE		SMC64_RVIC_FN(9)
+#define SMC64_RVIC_RESAMPLE		SMC64_RVIC_FN(10)
+
+#define RVIC_INFO_KEY_NR_TRUSTED_INTERRUPTS	0
+#define RVIC_INFO_KEY_NR_UNTRUSTED_INTERRUPTS	1
+
+#define RVIC_VERSION(M, m)		RVIx_VERSION((M), (m))
+
+#define RVIC_VERSION_MAJOR(v)		RVIx_VERSION_MAJOR((v))
+#define RVIC_VERSION_MINOR(v)		RVIx_VERSION_MINOR((v))
+
+#define RVIC_STATUS_REASON(c)		RVIx_STATUS_REASON((c))
+#define RVIC_STATUS_INDEX(c)		RVIx_STATUS_INDEX((c))
+
+#define RVIC_STATUS_SUCCESS		RVIx_STATUS_SUCCESS
+#define RVIC_STATUS_ERROR_PARAMETER	RVIx_STATUS_ERROR_PARAMETER
+#define RVIC_STATUS_INVALID_CPU		RVIx_STATUS_INVALID_CPU
+#define RVIC_STATUS_DISABLED		RVIx_STATUS_DISABLED
+#define RVIC_STATUS_NO_INTERRUPTS	RVIx_STATUS_NO_INTERRUPTS
+
+#endif /* __IRQCHIP_IRQ_RVIC_H__ */
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 02/23] irqchip/rvic: Add support for untrusted interrupt allocation
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
  2020-09-03 15:25 ` [PATCH 01/23] irqchip: Add Reduced Virtual Interrupt Controller driver Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-04 13:40   ` Jonathan Cameron
  2020-09-03 15:25 ` [PATCH 03/23] irqchip: Add Reduced Virtual Interrupt Distributor support Marc Zyngier
                   ` (20 subsequent siblings)
  22 siblings, 1 reply; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 drivers/irqchip/irq-rvic.c | 47 +++++++++++++++++++++++++++++++++++---
 1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-rvic.c b/drivers/irqchip/irq-rvic.c
index 6f37aa4318b6..2747a452202f 100644
--- a/drivers/irqchip/irq-rvic.c
+++ b/drivers/irqchip/irq-rvic.c
@@ -37,6 +37,8 @@ static DEFINE_PER_CPU(unsigned long *, trusted_masked);
 struct rvic_data {
 	struct fwnode_handle	*fwnode;
 	struct irq_domain	*domain;
+	unsigned long 		*bitmap;
+	struct mutex		lock;
 	unsigned int		nr_trusted;
 	unsigned int		nr_untrusted;
 };
@@ -356,9 +358,26 @@ static int rvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 	irq_hw_number_t hwirq;
 	int i, ret;
 
-	ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
-	if (ret)
-		return ret;
+	if (fwspec) {
+		ret = irq_domain_translate_twocell(domain, fwspec,
+						   &hwirq, &type);
+		if (ret)
+			return ret;
+	} else {
+		/* rVID wants untrusted interrupts */
+		mutex_lock(&rvic.lock);
+		hwirq = bitmap_find_next_zero_area(rvic.bitmap,
+						   rvic.nr_untrusted,
+						   0, nr_irqs, 0);
+		if (hwirq < rvic.nr_untrusted)
+			bitmap_set(rvic.bitmap, hwirq, nr_irqs);
+		mutex_unlock(&rvic.lock);
+
+		if (hwirq >= rvic.nr_untrusted)
+			return -ENOSPC;
+
+		hwirq += rvic.nr_trusted;
+	}
 
 	for (i = 0; i < nr_irqs; i++) {
 		unsigned int intid = hwirq + i;
@@ -376,6 +395,12 @@ static int rvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 					    domain->host_data,
 					    handle_percpu_devid_irq,
 					    NULL, NULL);
+		} else if (intid < (rvic.nr_trusted + rvic.nr_untrusted)) {
+			irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
+			irq_domain_set_info(domain, irq, intid, &rvic_chip,
+					    domain->host_data,
+					    handle_fasteoi_irq,
+					    NULL, NULL);
 		} else {
 			return -EINVAL;
 		}
@@ -391,6 +416,11 @@ static void rvic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
 
 	for (i = 0; i < nr_irqs; i++) {
 		struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
+		if (d->hwirq >= rvic.nr_trusted) {
+			mutex_lock(&rvic.lock);
+			__clear_bit(d->hwirq, rvic.bitmap);
+			mutex_unlock(&rvic.lock);
+		}
 		irq_set_handler(virq + i, NULL);
 		irq_domain_reset_irq_data(d);
 	}
@@ -523,6 +553,12 @@ static int __init rvic_init(struct device_node *node,
 		return -ENOMEM;
 	}
 
+	rvic.bitmap = bitmap_alloc(rvic.nr_untrusted, GFP_KERNEL | __GFP_ZERO);
+	if (!rvic.bitmap) {
+		pr_warn("Failed to allocate untrusted bitmap\n");
+		goto free_domain;
+	}
+
 	for_each_possible_cpu(cpu) {
 		unsigned long *map = bitmap_alloc(rvic.nr_trusted, GFP_KERNEL);
 
@@ -537,6 +573,8 @@ static int __init rvic_init(struct device_node *node,
 		per_cpu(trusted_masked, cpu) = map;
 	}
 
+	mutex_init(&rvic.lock);
+
 	rvic_smp_init(rvic.fwnode);
 	set_handle_irq(rvic_handle_irq);
 
@@ -546,6 +584,9 @@ static int __init rvic_init(struct device_node *node,
 	for_each_possible_cpu(cpu)
 		kfree(per_cpu(trusted_masked, cpu));
 
+	kfree(rvic.bitmap);
+
+free_domain:
 	irq_domain_remove(rvic.domain);
 
 	return -ENOMEM;
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 03/23] irqchip: Add Reduced Virtual Interrupt Distributor support
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
  2020-09-03 15:25 ` [PATCH 01/23] irqchip: Add Reduced Virtual Interrupt Controller driver Marc Zyngier
  2020-09-03 15:25 ` [PATCH 02/23] irqchip/rvic: Add support for untrusted interrupt allocation Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-04 13:56   ` Jonathan Cameron
  2020-09-03 15:25 ` [PATCH 04/23] irqchip/rvid: Add PCI MSI support Marc Zyngier
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 drivers/irqchip/Kconfig          |   6 +
 drivers/irqchip/Makefile         |   1 +
 drivers/irqchip/irq-rvid.c       | 259 +++++++++++++++++++++++++++++++
 include/linux/irqchip/irq-rvic.h |  19 +++
 4 files changed, 285 insertions(+)
 create mode 100644 drivers/irqchip/irq-rvid.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 348ff1d06651..731e8da9ae0c 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -67,6 +67,12 @@ config ARM_RVIC
 	select IRQ_DOMAIN_HIERARCHY
 	select GENERIC_IRQ_EFFECTIVE_AFF_MASK
 
+config ARM_RVID
+	bool
+	default ARM64
+	select IRQ_DOMAIN_HIERARCHY
+	select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+
 config ARM_VIC
 	bool
 	select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index d2b280efd2e0..cbcc23f92d31 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_PARTITION_PERCPU)		+= irq-partition-percpu.o
 obj-$(CONFIG_HISILICON_IRQ_MBIGEN)	+= irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
 obj-$(CONFIG_ARM_RVIC)			+= irq-rvic.o
+obj-$(CONFIG_ARM_RVID)			+= irq-rvid.o
 obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
 obj-$(CONFIG_ARMADA_370_XP_IRQ)		+= irq-armada-370-xp.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-rvid.c b/drivers/irqchip/irq-rvid.c
new file mode 100644
index 000000000000..953f654e58d4
--- /dev/null
+++ b/drivers/irqchip/irq-rvid.c
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2020 Google LLC.
+ * Author: Marc Zyngier <maz@kernel.org>
+ */
+
+#define pr_fmt(fmt)	"rVID: " fmt
+
+#include <linux/arm-smccc.h>
+#include <linux/cpuhotplug.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+
+#include <linux/irqchip/irq-rvic.h>
+
+struct rvid_data {
+	struct fwnode_handle	*fwnode;
+	struct irq_domain	*domain;
+};
+
+static struct rvid_data rvid;
+
+static inline int rvid_version(unsigned long *version)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVID_VERSION, &res);
+	if (res.a0 == RVID_STATUS_SUCCESS)
+		*version = res.a1;
+	return res.a0;
+}
+
+static inline int rvid_map(unsigned long input,
+			   unsigned long target, unsigned long intid)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVID_MAP, input, target, intid, &res);
+	return res.a0;
+}
+
+static inline int rvid_unmap(unsigned long input)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC64_RVID_UNMAP, input, &res);
+	return res.a0;
+}
+
+static int rvid_irq_set_affinity(struct irq_data *data,
+				 const struct cpumask *mask_val,
+				 bool force)
+{
+	unsigned int old_cpu, cpu;
+	bool masked, pending;
+	int err = 0, ret;
+	u64 mpidr;
+
+	if (force)
+		cpu = cpumask_first(mask_val);
+	else
+		cpu = cpumask_any_and(mask_val, cpu_online_mask);
+
+	if (cpu >= nr_cpu_ids)
+		return -EINVAL;
+
+	mpidr = cpu_logical_map(cpu) & MPIDR_HWID_BITMASK;
+	old_cpu = cpumask_first(data->common->effective_affinity);
+	if (cpu == old_cpu)
+		return 0;
+
+	/* Mask on source */
+	masked = irqd_irq_masked(data);
+	if (!masked)
+		irq_chip_mask_parent(data);
+
+	/* Switch to target */
+	irq_data_update_effective_affinity(data, cpumask_of(cpu));
+
+	/* Mask on target */
+	irq_chip_mask_parent(data);
+
+	/* Map the input signal to the new target */
+	ret = rvid_map(data->hwirq, mpidr, data->parent_data->hwirq);
+	if (ret != RVID_STATUS_SUCCESS) {
+		err = -ENXIO;
+		goto unmask;
+	}
+
+	/* Back to the source */
+	irq_data_update_effective_affinity(data, cpumask_of(old_cpu));
+
+	/* Sample pending state and clear it if necessary */
+	err = irq_chip_get_parent_state(data, IRQCHIP_STATE_PENDING, &pending);
+	if (err)
+		goto unmask;
+	if (pending)
+		irq_chip_set_parent_state(data, IRQCHIP_STATE_PENDING, false);
+
+	/*
+	 * To the target again (for good this time), propagating the
+	 * pending bit if required.
+	 */
+	irq_data_update_effective_affinity(data, cpumask_of(cpu));
+	if (pending)
+		irq_chip_set_parent_state(data, IRQCHIP_STATE_PENDING, true);
+unmask:
+	/* Propagate the masking state */
+	if (!masked)
+		irq_chip_unmask_parent(data);
+
+	return err;
+}
+
+static struct irq_chip rvid_chip = {
+	.name			= "rvid",
+	.irq_mask		= irq_chip_mask_parent,
+	.irq_unmask		= irq_chip_unmask_parent,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_get_irqchip_state	= irq_chip_get_parent_state,
+	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
+	.irq_set_type		= irq_chip_set_type_parent,
+	.irq_set_affinity	= rvid_irq_set_affinity,
+};
+
+static int rvid_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+				 unsigned int nr_irqs, void *arg)
+{
+	struct irq_fwspec *fwspec = arg;
+	unsigned int type = IRQ_TYPE_NONE;
+	irq_hw_number_t hwirq;
+	int i, ret;
+
+	ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < nr_irqs; i++) {
+		unsigned int intid = hwirq + i;
+		unsigned int irq = virq + i;
+
+		/* Get the rVIC to allocate any untrusted intid */
+		ret = irq_domain_alloc_irqs_parent(domain, irq, 1, NULL);
+		if (WARN_ON(ret))
+			return ret;
+
+		irq_domain_set_hwirq_and_chip(domain, irq, intid,
+					      &rvid_chip, &rvid);
+		irqd_set_affinity_on_activate(irq_get_irq_data(irq));
+	}
+
+	return 0;
+}
+
+static void rvid_irq_domain_free(struct irq_domain *domain, unsigned int virq,
+				 unsigned int nr_irqs)
+{
+	int i;
+
+	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+
+	for (i = 0; i < nr_irqs; i++) {
+		struct irq_data *d;
+
+		d = irq_domain_get_irq_data(domain, virq + i);
+		irq_set_handler(virq + i, NULL);
+		irq_domain_reset_irq_data(d);
+	}
+}
+
+static int rvid_irq_domain_activate(struct irq_domain *domain,
+				    struct irq_data *data, bool reserve)
+{
+	unsigned long ret;
+	int cpu, err = 0;
+	u64 mpidr;
+
+	cpu = get_cpu();
+	mpidr = cpu_logical_map(cpu) & MPIDR_HWID_BITMASK;
+
+	/* Map the input signal */
+	ret = rvid_map(data->hwirq, mpidr, data->parent_data->hwirq);
+	if (ret != RVID_STATUS_SUCCESS) {
+		err = -ENXIO;
+		goto out;
+	}
+
+	irq_data_update_effective_affinity(data, cpumask_of(cpu));
+
+out:
+	put_cpu();
+	return err;
+}
+
+static void rvid_irq_domain_deactivate(struct irq_domain *domain,
+				       struct irq_data *data)
+{
+	rvid_unmap(data->hwirq);
+}
+
+static const struct irq_domain_ops rvid_irq_domain_ops = {
+	.translate	= irq_domain_translate_onecell,
+	.alloc		= rvid_irq_domain_alloc,
+	.free		= rvid_irq_domain_free,
+	.activate	= rvid_irq_domain_activate,
+	.deactivate	= rvid_irq_domain_deactivate,
+};
+
+static int __init rvid_init(struct device_node *node,
+			    struct device_node *parent)
+{
+	struct irq_domain *parent_domain;
+	unsigned long ret, version;
+
+	if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_1) {
+		pr_err("SMCCC 1.1 required, aborting\n");
+		return -EINVAL;
+	}
+
+	if (!parent)
+		return -ENXIO;
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain)
+		return -ENXIO;
+
+	rvid.fwnode = of_node_to_fwnode(node);
+
+	ret = rvid_version(&version);
+	if (ret != RVID_STATUS_SUCCESS) {
+		pr_err("error retrieving version (%ld, %ld)\n",
+		       RVID_STATUS_REASON(ret), RVID_STATUS_INDEX(ret));
+		return -ENXIO;
+	}
+
+	if (version < RVID_VERSION(0, 3)) {
+		pr_err("version (%ld, %ld) too old, expected min. (%d, %d)\n",
+		       RVID_VERSION_MAJOR(version), RVID_VERSION_MINOR(version),
+		       0, 3);
+		return -ENXIO;
+	}
+
+	pr_info("distributing interrupts to %pOF\n", parent);
+
+	rvid.domain = irq_domain_create_hierarchy(parent_domain, 0, 0,
+						  rvid.fwnode,
+						  &rvid_irq_domain_ops, &rvid);
+	if (!rvid.domain) {
+		pr_warn("Failed to allocate irq domain\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(rvic, "arm,rvid", rvid_init);
diff --git a/include/linux/irqchip/irq-rvic.h b/include/linux/irqchip/irq-rvic.h
index 0176ca7d3c30..4545c1e89741 100644
--- a/include/linux/irqchip/irq-rvic.h
+++ b/include/linux/irqchip/irq-rvic.h
@@ -74,4 +74,23 @@
 #define RVIC_STATUS_DISABLED		RVIx_STATUS_DISABLED
 #define RVIC_STATUS_NO_INTERRUPTS	RVIx_STATUS_NO_INTERRUPTS
 
+/* rVID functions */
+#define SMC64_RVID_BASE			0xc5000100
+#define SMC64_RVID_FN(n)		(SMC64_RVID_BASE + (n))
+
+#define SMC64_RVID_VERSION		SMC64_RVID_FN(0)
+#define SMC64_RVID_MAP			SMC64_RVID_FN(1)
+#define SMC64_RVID_UNMAP		SMC64_RVID_FN(2)
+
+#define RVID_VERSION(M, m)		RVIx_VERSION((M), (m))
+
+#define RVID_VERSION_MAJOR(v)		RVIx_VERSION_MAJOR((v))
+#define RVID_VERSION_MINOR(v)		RVIx_VERSION_MINOR((v))
+
+#define RVID_STATUS_REASON(c)		RVIx_STATUS_REASON((c))
+#define RVID_STATUS_INDEX(c)		RVIx_STATUS_INDEX((c))
+
+#define RVID_STATUS_SUCCESS		RVIx_STATUS_SUCCESS
+#define RVID_STATUS_ERROR_PARAMETER	RVIx_STATUS_ERROR_PARAMETER
+
 #endif /* __IRQCHIP_IRQ_RVIC_H__ */
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 04/23] irqchip/rvid: Add PCI MSI support
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (2 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 03/23] irqchip: Add Reduced Virtual Interrupt Distributor support Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-04 14:15   ` Jonathan Cameron
  2020-09-03 15:25 ` [PATCH 05/23] KVM: arm64: Move GIC model out of the distributor Marc Zyngier
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 drivers/irqchip/irq-rvid.c | 182 +++++++++++++++++++++++++++++++++++++
 1 file changed, 182 insertions(+)

diff --git a/drivers/irqchip/irq-rvid.c b/drivers/irqchip/irq-rvid.c
index 953f654e58d4..250f95ad1a09 100644
--- a/drivers/irqchip/irq-rvid.c
+++ b/drivers/irqchip/irq-rvid.c
@@ -12,12 +12,19 @@
 #include <linux/irq.h>
 #include <linux/irqchip.h>
 #include <linux/irqdomain.h>
+#include <linux/msi.h>
 
 #include <linux/irqchip/irq-rvic.h>
 
 struct rvid_data {
 	struct fwnode_handle	*fwnode;
 	struct irq_domain	*domain;
+	struct irq_domain	*msi_domain;
+	struct irq_domain	*pci_domain;
+	unsigned long		*msi_map;
+	struct mutex		msi_lock;
+	u32			msi_base;
+	u32			msi_nr;
 };
 
 static struct rvid_data rvid;
@@ -209,6 +216,177 @@ static const struct irq_domain_ops rvid_irq_domain_ops = {
 	.deactivate	= rvid_irq_domain_deactivate,
 };
 
+#ifdef CONFIG_PCI_MSI
+/*
+ * The MSI irqchip is completely transparent. The only purpose of the
+ * corresponding irq domain is to provide the MSI allocator, and feed
+ * the allocated inputs to the main rVID irq domain for mapping at the
+ * rVIC level.
+ */
+static struct irq_chip rvid_msi_chip = {
+	.name			= "rvid-MSI",
+	.irq_mask		= irq_chip_mask_parent,
+	.irq_unmask		= irq_chip_unmask_parent,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_get_irqchip_state	= irq_chip_get_parent_state,
+	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
+	.irq_set_type		= irq_chip_set_type_parent,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+};
+
+static int rvid_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+				 unsigned int nr_irqs, void *arg)
+{
+	int ret, hwirq, i;
+
+	mutex_lock(&rvid.msi_lock);
+	hwirq = bitmap_find_free_region(rvid.msi_map, rvid.msi_nr,
+					get_count_order(nr_irqs));
+	mutex_unlock(&rvid.msi_lock);
+
+	if (hwirq < 0)
+		return -ENOSPC;
+
+	for (i = 0; i < nr_irqs; i++) {
+		/* Use the rVID domain to map the input to something */
+		struct irq_fwspec fwspec = (struct irq_fwspec) {
+			.fwnode		= domain->parent->fwnode,
+			.param_count	= 1,
+			.param[0]	= rvid.msi_base + hwirq + i,
+		};
+
+		ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &fwspec);
+		if (WARN_ON(ret))
+			goto out;
+
+		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+					      &rvid_msi_chip, &rvid);
+	}
+
+	return 0;
+
+out:
+	mutex_lock(&rvid.msi_lock);
+	bitmap_release_region(rvid.msi_map, hwirq, get_count_order(nr_irqs));
+	mutex_unlock(&rvid.msi_lock);
+
+	return ret;
+}
+
+static void rvid_msi_domain_free(struct irq_domain *domain, unsigned int virq,
+				 unsigned int nr_irqs)
+{
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+	irq_hw_number_t hwirq = d->hwirq;
+
+	/* This is a bit cheeky, but hey, recursion never hurt anyone... */
+	rvid_irq_domain_free(domain, virq, nr_irqs);
+
+	mutex_lock(&rvid.msi_lock);
+	bitmap_release_region(rvid.msi_map, hwirq, get_count_order(nr_irqs));
+	mutex_unlock(&rvid.msi_lock);
+}
+
+static struct irq_domain_ops rvid_msi_domain_ops = {
+	.alloc		= rvid_msi_domain_alloc,
+	.free		= rvid_msi_domain_free,
+};
+
+/*
+ * The PCI irq chip only provides the minimal stuff, as most of the
+ * other methods will be provided as defaults.
+ */
+static void rvid_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	/* Random address, the rVID doesn't really have a doorbell */
+	msg->address_hi = 0;
+	msg->address_lo = 0xba5e0000;
+
+	/*
+	 * We are called from the PCI domain, and what we program in
+	 * the device is the rVID input pin, which is located two
+	 * levels down in the interrupt chain (PCI -> MSI -> rVID).
+	 */
+	msg->data = data->parent_data->parent_data->hwirq;
+}
+
+static void rvid_pci_mask(struct irq_data *d)
+{
+	pci_msi_mask_irq(d);
+	irq_chip_mask_parent(d);
+}
+
+static void rvid_pci_unmask(struct irq_data *d)
+{
+	pci_msi_unmask_irq(d);
+	irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip rvid_pci_chip = {
+	.name			= "PCI-MSI",
+	.irq_mask		= rvid_pci_mask,
+	.irq_unmask		= rvid_pci_unmask,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_compose_msi_msg	= rvid_compose_msi_msg,
+	.irq_write_msi_msg	= pci_msi_domain_write_msg,
+};
+
+static struct msi_domain_info rvid_pci_domain_info = {
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+		   MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI),
+	.chip	= &rvid_pci_chip,
+};
+
+static void __init rvid_msi_setup(struct device_node *np)
+{
+	if (!of_property_read_bool(np, "msi-controller"))
+		return;
+
+	if (of_property_read_u32_index(np, "msi-range", 0, &rvid.msi_base) ||
+	    of_property_read_u32_index(np, "msi-range", 1, &rvid.msi_nr)) {
+		pr_err("Invalid or missing msi-range\n");
+		return;
+	}
+
+	mutex_init(&rvid.msi_lock);
+
+	rvid.msi_map = bitmap_alloc(rvid.msi_nr, GFP_KERNEL | __GFP_ZERO);
+	if (!rvid.msi_map)
+		return;
+
+	rvid.msi_domain = irq_domain_create_hierarchy(rvid.domain, 0, 0,
+						      rvid.fwnode,
+						      &rvid_msi_domain_ops,
+						      &rvid);
+	if (!rvid.msi_domain) {
+		pr_err("Failed to allocate MSI domain\n");
+		goto out;
+	}
+
+	irq_domain_update_bus_token(rvid.msi_domain, DOMAIN_BUS_NEXUS);
+
+	rvid.pci_domain = pci_msi_create_irq_domain(rvid.domain->fwnode,
+						    &rvid_pci_domain_info,
+						    rvid.msi_domain);
+	if (!rvid.pci_domain) {
+		pr_err("Failed to allocate PCI domain\n");
+		goto out;
+	}
+
+	pr_info("MSIs available as inputs [%d:%d]\n",
+		rvid.msi_base, rvid.msi_base + rvid.msi_nr - 1);
+	return;
+
+out:
+	if (rvid.msi_domain)
+		irq_domain_remove(rvid.msi_domain);
+	kfree(rvid.msi_map);
+}
+#else
+static inline void rvid_msi_setup(struct device_node *np) {}
+#endif
+
 static int __init rvid_init(struct device_node *node,
 			    struct device_node *parent)
 {
@@ -253,6 +431,10 @@ static int __init rvid_init(struct device_node *node,
 		return -ENOMEM;
 	}
 
+	irq_domain_update_bus_token(rvid.domain, DOMAIN_BUS_WIRED);
+
+	rvid_msi_setup(node);
+
 	return 0;
 }
 
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 05/23] KVM: arm64: Move GIC model out of the distributor
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (3 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 04/23] irqchip/rvid: Add PCI MSI support Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-04 14:37   ` Jonathan Cameron
  2020-09-03 15:25 ` [PATCH 06/23] KVM: arm64: vgic-v3: Move early init to kvm_vgic_create() Marc Zyngier
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

In order to allow more than just GIC implementations in the future,
let's move the GIC model outside of the distributor. This also
allows us to back irqchip_in_kernel() with its own irqchip type
(IRQCHIP_USER), removing another field from the distributor.

New helpers are provided as a convenience.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_host.h     |  2 ++
 arch/arm64/include/asm/kvm_irq.h      | 20 ++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic-debug.c      |  5 +++--
 arch/arm64/kvm/vgic/vgic-init.c       | 26 ++++++++++++--------------
 arch/arm64/kvm/vgic/vgic-kvm-device.c | 16 ++++++++++++----
 arch/arm64/kvm/vgic/vgic-mmio-v3.c    |  2 +-
 arch/arm64/kvm/vgic/vgic-mmio.c       | 10 ++++------
 arch/arm64/kvm/vgic/vgic-v3.c         | 20 ++++++++------------
 include/kvm/arm_vgic.h                |  5 -----
 9 files changed, 62 insertions(+), 44 deletions(-)
 create mode 100644 arch/arm64/include/asm/kvm_irq.h

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index e52c927aade5..f0e30e12b523 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -24,6 +24,7 @@
 #include <asm/fpsimd.h>
 #include <asm/kvm.h>
 #include <asm/kvm_asm.h>
+#include <asm/kvm_irq.h>
 #include <asm/thread_info.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -98,6 +99,7 @@ struct kvm_arch {
 	int max_vcpus;
 
 	/* Interrupt controller */
+	enum kvm_irqchip_type	irqchip_type;
 	struct vgic_dist	vgic;
 
 	/* Mandated version of PSCI */
diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
new file mode 100644
index 000000000000..46bffb6026f8
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 - Google LLC
+ * Author: Marc Zyngier <maz@kernel.org>
+ */
+
+#ifndef __ARM64_KVM_IRQ_H__
+#define __ARM64_KVM_IRQ_H__
+
+enum kvm_irqchip_type {
+	IRQCHIP_USER,		/* Implemented in userspace */
+	IRQCHIP_GICv2,		/* v2 on v2, or v2 on v3 */
+	IRQCHIP_GICv3,		/* v3 on v3 */
+};
+
+#define irqchip_in_kernel(k)	((k)->arch.irqchip_type != IRQCHIP_USER)
+#define irqchip_is_gic_v2(k)	((k)->arch.irqchip_type == IRQCHIP_GICv2)
+#define irqchip_is_gic_v3(k)	((k)->arch.irqchip_type == IRQCHIP_GICv3)
+
+#endif
diff --git a/arch/arm64/kvm/vgic/vgic-debug.c b/arch/arm64/kvm/vgic/vgic-debug.c
index b13a9e3f99dd..2d19fd55fc7b 100644
--- a/arch/arm64/kvm/vgic/vgic-debug.c
+++ b/arch/arm64/kvm/vgic/vgic-debug.c
@@ -61,7 +61,7 @@ static void iter_init(struct kvm *kvm, struct vgic_state_iter *iter,
 
 	iter->nr_cpus = nr_cpus;
 	iter->nr_spis = kvm->arch.vgic.nr_spis;
-	if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
+	if (irqchip_is_gic_v3(kvm)) {
 		iter->nr_lpis = vgic_copy_lpi_list(kvm, NULL, &iter->lpi_array);
 		if (iter->nr_lpis < 0)
 			iter->nr_lpis = 0;
@@ -142,7 +142,8 @@ static void vgic_debug_stop(struct seq_file *s, void *v)
 
 static void print_dist_state(struct seq_file *s, struct vgic_dist *dist)
 {
-	bool v3 = dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3;
+	struct kvm *kvm = container_of(dist, struct kvm, arch.vgic);
+	bool v3 = irqchip_is_gic_v3(kvm);
 
 	seq_printf(s, "Distributor\n");
 	seq_printf(s, "===========\n");
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 32e32d67a127..8157171b8af3 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -106,8 +106,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 		goto out_unlock;
 	}
 
-	kvm->arch.vgic.in_kernel = true;
-	kvm->arch.vgic.vgic_model = type;
+	kvm->arch.irqchip_type = (type == KVM_DEV_TYPE_ARM_VGIC_V2 ?
+				  IRQCHIP_GICv2 : IRQCHIP_GICv3);
 
 	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
 
@@ -155,12 +155,12 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
 		irq->vcpu = NULL;
 		irq->target_vcpu = vcpu0;
 		kref_init(&irq->refcount);
-		switch (dist->vgic_model) {
-		case KVM_DEV_TYPE_ARM_VGIC_V2:
+		switch (kvm->arch.irqchip_type) {
+		case IRQCHIP_GICv2:
 			irq->targets = 0;
 			irq->group = 0;
 			break;
-		case KVM_DEV_TYPE_ARM_VGIC_V3:
+		case IRQCHIP_GICv3:
 			irq->mpidr = 0;
 			irq->group = 1;
 			break;
@@ -185,7 +185,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
 int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	int ret = 0;
 	int i;
 
@@ -225,7 +224,7 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
 	 * If we are creating a VCPU with a GICv3 we must also register the
 	 * KVM io device for the redistributor that belongs to this VCPU.
 	 */
-	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
+	if (irqchip_is_gic_v3(vcpu->kvm)) {
 		mutex_lock(&vcpu->kvm->lock);
 		ret = vgic_register_redist_iodev(vcpu);
 		mutex_unlock(&vcpu->kvm->lock);
@@ -278,12 +277,12 @@ int vgic_init(struct kvm *kvm)
 
 		for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
 			struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
-			switch (dist->vgic_model) {
-			case KVM_DEV_TYPE_ARM_VGIC_V3:
+			switch (kvm->arch.irqchip_type) {
+			case IRQCHIP_GICv3:
 				irq->group = 1;
 				irq->mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
 				break;
-			case KVM_DEV_TYPE_ARM_VGIC_V2:
+			case IRQCHIP_GICv2:
 				irq->group = 0;
 				irq->targets = 1U << idx;
 				break;
@@ -336,7 +335,7 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
 	dist->spis = NULL;
 	dist->nr_spis = 0;
 
-	if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
+	if (irqchip_is_gic_v3(kvm)) {
 		list_for_each_entry_safe(rdreg, next, &dist->rd_regions, list) {
 			list_del(&rdreg->list);
 			kfree(rdreg);
@@ -402,7 +401,7 @@ int vgic_lazy_init(struct kvm *kvm)
 		 * be explicitly initialized once setup with the respective
 		 * KVM device call.
 		 */
-		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
+		if (!irqchip_is_gic_v2(kvm))
 			return -EBUSY;
 
 		mutex_lock(&kvm->lock);
@@ -425,14 +424,13 @@ int vgic_lazy_init(struct kvm *kvm)
  */
 int kvm_vgic_map_resources(struct kvm *kvm)
 {
-	struct vgic_dist *dist = &kvm->arch.vgic;
 	int ret = 0;
 
 	mutex_lock(&kvm->lock);
 	if (!irqchip_in_kernel(kvm))
 		goto out;
 
-	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+	if (irqchip_is_gic_v2(kvm))
 		ret = vgic_v2_map_resources(kvm);
 	else
 		ret = vgic_v3_map_resources(kvm);
diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index 44419679f91a..928afb224540 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -31,10 +31,18 @@ int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
 
 static int vgic_check_type(struct kvm *kvm, int type_needed)
 {
-	if (kvm->arch.vgic.vgic_model != type_needed)
-		return -ENODEV;
-	else
-		return 0;
+	switch (type_needed) {
+	case KVM_DEV_TYPE_ARM_VGIC_V2:
+		if (irqchip_is_gic_v2(kvm))
+			return 0;
+		break;
+	case KVM_DEV_TYPE_ARM_VGIC_V3:
+		if (irqchip_is_gic_v3(kvm))
+			return 0;
+		break;
+	}
+
+	return -ENODEV;
 }
 
 /**
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index 5c786b915cd3..6234e1409b4d 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -42,7 +42,7 @@ bool vgic_has_its(struct kvm *kvm)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
 
-	if (dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
+	if (!irqchip_is_gic_v3(kvm))
 		return false;
 
 	return dist->has_its;
diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c
index b2d73fc0d1ef..865f12030ab5 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio.c
@@ -263,8 +263,7 @@ unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
 
 static bool is_vgic_v2_sgi(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
 {
-	return (vgic_irq_is_sgi(irq->intid) &&
-		vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2);
+	return (vgic_irq_is_sgi(irq->intid) && irqchip_is_gic_v2(vcpu->kvm));
 }
 
 void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
@@ -450,7 +449,7 @@ int vgic_uaccess_write_cpending(struct kvm_vcpu *vcpu,
  */
 static void vgic_access_active_prepare(struct kvm_vcpu *vcpu, u32 intid)
 {
-	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3 ||
+	if (irqchip_is_gic_v3(vcpu->kvm) ||
 	    intid >= VGIC_NR_PRIVATE_IRQS)
 		kvm_arm_halt_guest(vcpu->kvm);
 }
@@ -458,7 +457,7 @@ static void vgic_access_active_prepare(struct kvm_vcpu *vcpu, u32 intid)
 /* See vgic_access_active_prepare */
 static void vgic_access_active_finish(struct kvm_vcpu *vcpu, u32 intid)
 {
-	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3 ||
+	if (irqchip_is_gic_v3(vcpu->kvm) ||
 	    intid >= VGIC_NR_PRIVATE_IRQS)
 		kvm_arm_resume_guest(vcpu->kvm);
 }
@@ -539,7 +538,6 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 		 */
 		irq->active = false;
 	} else {
-		u32 model = vcpu->kvm->arch.vgic.vgic_model;
 		u8 active_source;
 
 		irq->active = active;
@@ -557,7 +555,7 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 		 */
 		active_source = (requester_vcpu) ? requester_vcpu->vcpu_id : 0;
 
-		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
+		if (irqchip_is_gic_v2(vcpu->kvm) &&
 		    active && vgic_irq_is_sgi(irq->intid))
 			irq->active_source = active_source;
 	}
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 76e2d85789ed..c6fdb1222453 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -32,7 +32,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3;
-	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	bool is_v3 = irqchip_is_gic_v3(vcpu->kvm);
 	int lr;
 
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
@@ -48,7 +48,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 		cpuid = val & GICH_LR_PHYSID_CPUID;
 		cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
 
-		if (model == KVM_DEV_TYPE_ARM_VGIC_V3) {
+		if (is_v3) {
 			intid = val & ICH_LR_VIRTUAL_ID_MASK;
 		} else {
 			intid = val & GICH_LR_VIRTUALID;
@@ -117,12 +117,11 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 /* Requires the irq to be locked already */
 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
 {
-	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	bool is_v2 = irqchip_is_gic_v2(vcpu->kvm);
 	u64 val = irq->intid;
 	bool allow_pending = true, is_v2_sgi;
 
-	is_v2_sgi = (vgic_irq_is_sgi(irq->intid) &&
-		     model == KVM_DEV_TYPE_ARM_VGIC_V2);
+	is_v2_sgi = (vgic_irq_is_sgi(irq->intid) && is_v2);
 
 	if (irq->active) {
 		val |= ICH_LR_ACTIVE_BIT;
@@ -163,8 +162,7 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
 		if (irq->config == VGIC_CONFIG_EDGE)
 			irq->pending_latch = false;
 
-		if (vgic_irq_is_sgi(irq->intid) &&
-		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+		if (vgic_irq_is_sgi(irq->intid) && is_v2) {
 			u32 src = ffs(irq->source);
 
 			if (WARN_RATELIMIT(!src, "No SGI source for INTID %d\n",
@@ -205,10 +203,9 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
-	u32 model = vcpu->kvm->arch.vgic.vgic_model;
 	u32 vmcr;
 
-	if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+	if (irqchip_is_gic_v2(vcpu->kvm)) {
 		vmcr = (vmcrp->ackctl << ICH_VMCR_ACK_CTL_SHIFT) &
 			ICH_VMCR_ACK_CTL_MASK;
 		vmcr |= (vmcrp->fiqen << ICH_VMCR_FIQ_EN_SHIFT) &
@@ -235,12 +232,11 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
-	u32 model = vcpu->kvm->arch.vgic.vgic_model;
 	u32 vmcr;
 
 	vmcr = cpu_if->vgic_vmcr;
 
-	if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+	if (irqchip_is_gic_v2(vcpu->kvm)) {
 		vmcrp->ackctl = (vmcr & ICH_VMCR_ACK_CTL_MASK) >>
 			ICH_VMCR_ACK_CTL_SHIFT;
 		vmcrp->fiqen = (vmcr & ICH_VMCR_FIQ_EN_MASK) >>
@@ -285,7 +281,7 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 	 * Also, we don't support any form of IRQ/FIQ bypass.
 	 * This goes with the spec allowing the value to be RAO/WI.
 	 */
-	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
+	if (irqchip_is_gic_v3(vcpu->kvm)) {
 		vgic_v3->vgic_sre = (ICC_SRE_EL1_DIB |
 				     ICC_SRE_EL1_DFB |
 				     ICC_SRE_EL1_SRE);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index a8d8fdcd3723..88461ecfa854 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -201,13 +201,9 @@ struct vgic_redist_region {
 };
 
 struct vgic_dist {
-	bool			in_kernel;
 	bool			ready;
 	bool			initialized;
 
-	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
-	u32			vgic_model;
-
 	/* Implementation revision as reported in the GICD_IIDR */
 	u32			implementation_rev;
 
@@ -361,7 +357,6 @@ void kvm_vgic_load(struct kvm_vcpu *vcpu);
 void kvm_vgic_put(struct kvm_vcpu *vcpu);
 void kvm_vgic_vmcr_sync(struct kvm_vcpu *vcpu);
 
-#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 06/23] KVM: arm64: vgic-v3: Move early init to kvm_vgic_create()
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (4 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 05/23] KVM: arm64: Move GIC model out of the distributor Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-03 15:25 ` [PATCH 07/23] KVM: arm64: Add irqchip callback structure to kvm_arch Marc Zyngier
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

The current early init for the GIC is pretty silly. The data
it initializes only matters for GICv3, which is guaranteed to
be created via a kvm_create_device call. Given that,
it is pointless to initialize the data early, before userspace can
get a file descriptor and mess with it.

Move everything to kvm_vgic_create().

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/arm.c            |  2 --
 arch/arm64/kvm/vgic/vgic-init.c | 24 +++++-------------------
 include/kvm/arm_vgic.h          |  1 -
 3 files changed, 5 insertions(+), 22 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 46dc3d75cf13..41f98564f507 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -120,8 +120,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	if (ret)
 		goto out_free_stage2_pgd;
 
-	kvm_vgic_early_init(kvm);
-
 	/* The maximum number of VCPUs is limited by the host's GIC model */
 	kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
 
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 8157171b8af3..76cce0db63a7 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -39,25 +39,6 @@
  *   allocation is allowed there.
  */
 
-/* EARLY INIT */
-
-/**
- * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
- * @kvm: The VM whose VGIC districutor should be initialized
- *
- * Only do initialization of static structures that don't require any
- * allocation or sizing information from userspace.  vgic_init() called
- * kvm_vgic_dist_init() which takes care of the rest.
- */
-void kvm_vgic_early_init(struct kvm *kvm)
-{
-	struct vgic_dist *dist = &kvm->arch.vgic;
-
-	INIT_LIST_HEAD(&dist->lpi_list_head);
-	INIT_LIST_HEAD(&dist->lpi_translation_cache);
-	raw_spin_lock_init(&dist->lpi_list_lock);
-}
-
 /* CREATION */
 
 /**
@@ -72,6 +53,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 {
 	int i, ret;
 	struct kvm_vcpu *vcpu;
+	struct vgic_dist *dist = &kvm->arch.vgic;
 
 	if (irqchip_in_kernel(kvm))
 		return -EEXIST;
@@ -116,6 +98,10 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	else
 		INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
 
+	INIT_LIST_HEAD(&dist->lpi_list_head);
+	INIT_LIST_HEAD(&dist->lpi_translation_cache);
+	raw_spin_lock_init(&dist->lpi_list_lock);
+
 out_unlock:
 	unlock_all_vcpus(kvm);
 	return ret;
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 88461ecfa854..8d30fc645148 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -335,7 +335,6 @@ extern struct static_key_false vgic_v2_cpuif_trap;
 extern struct static_key_false vgic_v3_cpuif_trap;
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
-void kvm_vgic_early_init(struct kvm *kvm);
 int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
 void kvm_vgic_destroy(struct kvm *kvm);
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 07/23] KVM: arm64: Add irqchip callback structure to kvm_arch
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (5 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 06/23] KVM: arm64: vgic-v3: Move early init to kvm_vgic_create() Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-03 15:25 ` [PATCH 08/23] KVM: arm64: Move kvm_vgic_destroy to kvm_irqchip_flow Marc Zyngier
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

As we are about to abstract part of the vgic implementation in
order to make it more modular, let's start by adding a data
structure that will eventually contain interrupt controller
specific callbacks, as well as helpers to call them (or
gracefully skip them if they aren't implemented.

It is empty so far, so no functional changes are anticipated.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/include/asm/kvm_irq.h  | 29 +++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic-init.c   |  5 +++++
 3 files changed, 35 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index f0e30e12b523..52b502f3076f 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -100,6 +100,7 @@ struct kvm_arch {
 
 	/* Interrupt controller */
 	enum kvm_irqchip_type	irqchip_type;
+	struct kvm_irqchip_flow	irqchip_flow;
 	struct vgic_dist	vgic;
 
 	/* Mandated version of PSCI */
diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 46bffb6026f8..7a70bb803560 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -17,4 +17,33 @@ enum kvm_irqchip_type {
 #define irqchip_is_gic_v2(k)	((k)->arch.irqchip_type == IRQCHIP_GICv2)
 #define irqchip_is_gic_v3(k)	((k)->arch.irqchip_type == IRQCHIP_GICv3)
 
+struct kvm_irqchip_flow {
+};
+
+/*
+ * Macro galore. At the point this is included, the various types are
+ * not defined yet. Yes, this is terminally ugly.
+ */
+#define __kvm_irqchip_action(k, x, ...)					\
+	do {								\
+		if (likely((k)->arch.irqchip_flow.irqchip_##x))		\
+			(k)->arch.irqchip_flow.irqchip_##x(__VA_ARGS__); \
+	} while (0)
+
+#define __kvm_irqchip_action_ret(k, x, ...)				\
+	({								\
+		typeof ((k)->arch.irqchip_flow.irqchip_##x(__VA_ARGS__)) ret; \
+		ret = (likely((k)->arch.irqchip_flow.irqchip_##x) ?	\
+		       (k)->arch.irqchip_flow.irqchip_##x(__VA_ARGS__) : \
+		       0);						\
+									\
+		ret;							\
+	 })
+
+#define __vcpu_irqchip_action(v, ...)			\
+	__kvm_irqchip_action((v)->kvm, __VA_ARGS__)
+
+#define __vcpu_irqchip_action_ret(v, ...)		\
+	__kvm_irqchip_action_ret((v)->kvm, __VA_ARGS__)
+
 #endif
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 76cce0db63a7..6b8f0518c074 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -12,6 +12,9 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+static struct kvm_irqchip_flow vgic_irqchip_flow = {
+};
+
 /*
  * Initialization rules: there are multiple stages to the vgic
  * initialization, both for the distributor and the CPU interfaces.  The basic
@@ -98,6 +101,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	else
 		INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
 
+	kvm->arch.irqchip_flow = vgic_irqchip_flow;
+
 	INIT_LIST_HEAD(&dist->lpi_list_head);
 	INIT_LIST_HEAD(&dist->lpi_translation_cache);
 	raw_spin_lock_init(&dist->lpi_list_lock);
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 08/23] KVM: arm64: Move kvm_vgic_destroy to kvm_irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (6 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 07/23] KVM: arm64: Add irqchip callback structure to kvm_arch Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-03 15:25 ` [PATCH 09/23] KVM: arm64: Move kvm_vgic_vcpu_init() to irqchip_flow Marc Zyngier
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Let's start the VGIC split by moving the act of destroying it,
as it is simple and doesn't require much effort.

Whilst we're at it, make kvm_vgic_vcpu_destroy() static,
as it isn't called from anywhere else.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h | 4 ++++
 arch/arm64/kvm/arm.c             | 2 +-
 arch/arm64/kvm/vgic/vgic-init.c  | 7 +++++--
 include/kvm/arm_vgic.h           | 2 --
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 7a70bb803560..f83594257bc4 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -18,6 +18,7 @@ enum kvm_irqchip_type {
 #define irqchip_is_gic_v3(k)	((k)->arch.irqchip_type == IRQCHIP_GICv3)
 
 struct kvm_irqchip_flow {
+	void (*irqchip_destroy)(struct kvm *);
 };
 
 /*
@@ -46,4 +47,7 @@ struct kvm_irqchip_flow {
 #define __vcpu_irqchip_action_ret(v, ...)		\
 	__kvm_irqchip_action_ret((v)->kvm, __VA_ARGS__)
 
+#define kvm_irqchip_destroy(k)				\
+	__kvm_irqchip_action((k), destroy, (k))
+
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 41f98564f507..09b4bcb2c805 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -143,7 +143,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 {
 	int i;
 
-	kvm_vgic_destroy(kvm);
+	kvm_irqchip_destroy(kvm);
 
 	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
 		if (kvm->vcpus[i]) {
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 6b8f0518c074..4e2c23a7dab1 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -12,7 +12,10 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+static void kvm_vgic_destroy(struct kvm *kvm);
+
 static struct kvm_irqchip_flow vgic_irqchip_flow = {
+	.irqchip_destroy		= kvm_vgic_destroy,
 };
 
 /*
@@ -341,7 +344,7 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
 		vgic_v4_teardown(kvm);
 }
 
-void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
+static void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 
@@ -368,7 +371,7 @@ static void __kvm_vgic_destroy(struct kvm *kvm)
 	kvm_vgic_dist_destroy(kvm);
 }
 
-void kvm_vgic_destroy(struct kvm *kvm)
+static void kvm_vgic_destroy(struct kvm *kvm)
 {
 	mutex_lock(&kvm->lock);
 	__kvm_vgic_destroy(kvm);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 8d30fc645148..e8bdc304ec9b 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -337,8 +337,6 @@ extern struct static_key_false vgic_v3_cpuif_trap;
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
 int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
-void kvm_vgic_destroy(struct kvm *kvm);
-void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
 int kvm_vgic_map_resources(struct kvm *kvm);
 int kvm_vgic_hyp_init(void);
 void kvm_vgic_init_cpu_hardware(void);
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 09/23] KVM: arm64: Move kvm_vgic_vcpu_init() to irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (7 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 08/23] KVM: arm64: Move kvm_vgic_destroy to kvm_irqchip_flow Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-03 15:25 ` [PATCH 10/23] KVM: arm64: Move kvm_vgic_vcpu_[un]blocking() " Marc Zyngier
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Abstract kvm_vgic_vcpu_init() by moving it to the irqchip_flow
structure. This results in a minor change of the way we initialize
vcpus:

VCPUs created prior to the creation of the vgic device don't have
their local view of the vgic initialized. This means that on vgic
instantiation, we must "catch up" and initialise the CPU interfaces
for these vcpus. VCPUs created after the vgic device will follow
the unusual flow. Special care must be taken to accomodate the
different locking contexts though.

The function can then be made static and the irqchip_in_kernel()
test dropped, as we only get here if a vgic has been created.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h |  4 ++++
 arch/arm64/kvm/arm.c             |  2 +-
 arch/arm64/kvm/vgic/vgic-init.c  | 37 +++++++++++++++++++++++++-------
 include/kvm/arm_vgic.h           |  1 -
 4 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index f83594257bc4..09df1f46d4de 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -19,6 +19,7 @@ enum kvm_irqchip_type {
 
 struct kvm_irqchip_flow {
 	void (*irqchip_destroy)(struct kvm *);
+	int  (*irqchip_vcpu_init)(struct kvm_vcpu *);
 };
 
 /*
@@ -50,4 +51,7 @@ struct kvm_irqchip_flow {
 #define kvm_irqchip_destroy(k)				\
 	__kvm_irqchip_action((k), destroy, (k))
 
+#define kvm_irqchip_vcpu_init(v)			\
+	__vcpu_irqchip_action_ret((v), vcpu_init, (v))
+
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 09b4bcb2c805..d82d348a36c3 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -265,7 +265,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 
 	vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu;
 
-	err = kvm_vgic_vcpu_init(vcpu);
+	err = kvm_irqchip_vcpu_init(vcpu);
 	if (err)
 		return err;
 
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 4e2c23a7dab1..d845699c6966 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -12,10 +12,12 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+static int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
 static void kvm_vgic_destroy(struct kvm *kvm);
 
 static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_destroy		= kvm_vgic_destroy,
+	.irqchip_vcpu_init		= kvm_vgic_vcpu_init,
 };
 
 /*
@@ -45,6 +47,8 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
  *   allocation is allowed there.
  */
 
+static int __kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
+
 /* CREATION */
 
 /**
@@ -110,6 +114,17 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	INIT_LIST_HEAD(&dist->lpi_translation_cache);
 	raw_spin_lock_init(&dist->lpi_list_lock);
 
+	/*
+	 * vcpus may have been created before the GIC. Initialize
+	 * them. Careful that kvm->lock is held already on the
+	 * KVM_CREATE_DEVICE path, so use the non-locking version.
+	 */
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		ret = __kvm_vgic_vcpu_init(vcpu);
+		if (ret)
+			break;
+	}
+
 out_unlock:
 	unlock_all_vcpus(kvm);
 	return ret;
@@ -176,7 +191,7 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
  * Only do initialization, but do not actually enable the
  * VGIC CPU interface
  */
-int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
+static int __kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	int ret = 0;
@@ -211,18 +226,24 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
 		}
 	}
 
-	if (!irqchip_in_kernel(vcpu->kvm))
-		return 0;
-
 	/*
 	 * If we are creating a VCPU with a GICv3 we must also register the
 	 * KVM io device for the redistributor that belongs to this VCPU.
 	 */
-	if (irqchip_is_gic_v3(vcpu->kvm)) {
-		mutex_lock(&vcpu->kvm->lock);
+	if (irqchip_is_gic_v3(vcpu->kvm))
 		ret = vgic_register_redist_iodev(vcpu);
-		mutex_unlock(&vcpu->kvm->lock);
-	}
+
+	return ret;
+}
+
+static int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	int ret;
+
+	mutex_lock(&vcpu->kvm->lock);
+	ret = __kvm_vgic_vcpu_init(vcpu);
+	mutex_unlock(&vcpu->kvm->lock);
+
 	return ret;
 }
 
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index e8bdc304ec9b..b2fd0e39af11 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -335,7 +335,6 @@ extern struct static_key_false vgic_v2_cpuif_trap;
 extern struct static_key_false vgic_v3_cpuif_trap;
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
-int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
 int kvm_vgic_map_resources(struct kvm *kvm);
 int kvm_vgic_hyp_init(void);
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 10/23] KVM: arm64: Move kvm_vgic_vcpu_[un]blocking() to irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (8 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 09/23] KVM: arm64: Move kvm_vgic_vcpu_init() to irqchip_flow Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-03 15:25 ` [PATCH 11/23] KVM: arm64: Move kvm_vgic_vcpu_load/put() " Marc Zyngier
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Move the code dedicated to blocking/unblocking on WFI to
the vgic code itself, and abstract it via the irqchip_flow
structure.

No functional change.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h |  8 ++++++++
 arch/arm64/kvm/arm.c             | 19 ++-----------------
 arch/arm64/kvm/vgic/vgic-init.c  |  2 ++
 arch/arm64/kvm/vgic/vgic.c       | 25 ++++++++++++++++++++++---
 arch/arm64/kvm/vgic/vgic.h       |  3 +++
 include/kvm/arm_vgic.h           |  1 -
 6 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 09df1f46d4de..493b59dae256 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -20,6 +20,8 @@ enum kvm_irqchip_type {
 struct kvm_irqchip_flow {
 	void (*irqchip_destroy)(struct kvm *);
 	int  (*irqchip_vcpu_init)(struct kvm_vcpu *);
+	void (*irqchip_vcpu_blocking)(struct kvm_vcpu *);
+	void (*irqchip_vcpu_unblocking)(struct kvm_vcpu *);
 };
 
 /*
@@ -54,4 +56,10 @@ struct kvm_irqchip_flow {
 #define kvm_irqchip_vcpu_init(v)			\
 	__vcpu_irqchip_action_ret((v), vcpu_init, (v))
 
+#define kvm_irqchip_vcpu_blocking(v)			\
+	__vcpu_irqchip_action((v), vcpu_blocking, (v))
+
+#define kvm_irqchip_vcpu_unblocking(v)			\
+	__vcpu_irqchip_action((v), vcpu_unblocking, (v))
+
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index d82d348a36c3..b60265f575cd 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -295,27 +295,12 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
 {
-	/*
-	 * If we're about to block (most likely because we've just hit a
-	 * WFI), we need to sync back the state of the GIC CPU interface
-	 * so that we have the latest PMR and group enables. This ensures
-	 * that kvm_arch_vcpu_runnable has up-to-date data to decide
-	 * whether we have pending interrupts.
-	 *
-	 * For the same reason, we want to tell GICv4 that we need
-	 * doorbells to be signalled, should an interrupt become pending.
-	 */
-	preempt_disable();
-	kvm_vgic_vmcr_sync(vcpu);
-	vgic_v4_put(vcpu, true);
-	preempt_enable();
+	kvm_irqchip_vcpu_blocking(vcpu);
 }
 
 void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
 {
-	preempt_disable();
-	vgic_v4_load(vcpu);
-	preempt_enable();
+	kvm_irqchip_vcpu_unblocking(vcpu);
 }
 
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index d845699c6966..b519fb56a8cd 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -18,6 +18,8 @@ static void kvm_vgic_destroy(struct kvm *kvm);
 static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_destroy		= kvm_vgic_destroy,
 	.irqchip_vcpu_init		= kvm_vgic_vcpu_init,
+	.irqchip_vcpu_blocking		= kvm_vgic_vcpu_blocking,
+	.irqchip_vcpu_unblocking	= kvm_vgic_vcpu_unblocking,
 };
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index c3643b7f101b..f576273c5608 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -939,15 +939,34 @@ void kvm_vgic_put(struct kvm_vcpu *vcpu)
 		vgic_v3_put(vcpu);
 }
 
-void kvm_vgic_vmcr_sync(struct kvm_vcpu *vcpu)
+void kvm_vgic_vcpu_blocking(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
-		return;
+	/*
+	 * If we're about to block (most likely because we've just hit a
+	 * WFI), we need to sync back the state of the GIC CPU interface
+	 * so that we have the latest PMR and group enables. This ensures
+	 * that kvm_arch_vcpu_runnable has up-to-date data to decide
+	 * whether we have pending interrupts.
+	 *
+	 * For the same reason, we want to tell GICv4 that we need
+	 * doorbells to be signalled, should an interrupt become pending.
+	 */
+	preempt_disable();
 
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_vmcr_sync(vcpu);
 	else
 		vgic_v3_vmcr_sync(vcpu);
+
+	vgic_v4_put(vcpu, true);
+	preempt_enable();
+}
+
+void kvm_vgic_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+	preempt_disable();
+	vgic_v4_load(vcpu);
+	preempt_enable();
 }
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 64fcd7511110..d8a0e3729de4 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -227,6 +227,9 @@ void vgic_v3_load(struct kvm_vcpu *vcpu);
 void vgic_v3_put(struct kvm_vcpu *vcpu);
 void vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu);
 
+void kvm_vgic_vcpu_blocking(struct kvm_vcpu *vcpu);
+void kvm_vgic_vcpu_unblocking(struct kvm_vcpu *vcpu);
+
 bool vgic_has_its(struct kvm *kvm);
 int kvm_vgic_register_its_device(void);
 void vgic_enable_lpis(struct kvm_vcpu *vcpu);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index b2fd0e39af11..2bffc2d513ef 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -351,7 +351,6 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
 void kvm_vgic_load(struct kvm_vcpu *vcpu);
 void kvm_vgic_put(struct kvm_vcpu *vcpu);
-void kvm_vgic_vmcr_sync(struct kvm_vcpu *vcpu);
 
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 11/23] KVM: arm64: Move kvm_vgic_vcpu_load/put() to irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (9 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 10/23] KVM: arm64: Move kvm_vgic_vcpu_[un]blocking() " Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-03 15:25 ` [PATCH 12/23] KVM: arm64: Move kvm_vgic_vcpu_pending_irq() " Marc Zyngier
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Abstract the calls to kvm_vgic_vcpu_load/put() via the irqchip_flow
structure.

No functional change.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h | 8 ++++++++
 arch/arm64/kvm/arm.c             | 4 ++--
 arch/arm64/kvm/vgic/vgic-init.c  | 2 ++
 arch/arm64/kvm/vgic/vgic.h       | 3 +++
 include/kvm/arm_vgic.h           | 3 ---
 5 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 493b59dae256..50dfd641cd67 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -22,6 +22,8 @@ struct kvm_irqchip_flow {
 	int  (*irqchip_vcpu_init)(struct kvm_vcpu *);
 	void (*irqchip_vcpu_blocking)(struct kvm_vcpu *);
 	void (*irqchip_vcpu_unblocking)(struct kvm_vcpu *);
+	void (*irqchip_vcpu_load)(struct kvm_vcpu *);
+	void (*irqchip_vcpu_put)(struct kvm_vcpu *);
 };
 
 /*
@@ -62,4 +64,10 @@ struct kvm_irqchip_flow {
 #define kvm_irqchip_vcpu_unblocking(v)			\
 	__vcpu_irqchip_action((v), vcpu_unblocking, (v))
 
+#define kvm_irqchip_vcpu_load(v)			\
+	__vcpu_irqchip_action((v), vcpu_load, (v))
+
+#define kvm_irqchip_vcpu_put(v)				\
+	__vcpu_irqchip_action((v), vcpu_put, (v))
+
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index b60265f575cd..84d48c312b84 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -322,7 +322,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
 	vcpu->cpu = cpu;
 
-	kvm_vgic_load(vcpu);
+	kvm_irqchip_vcpu_load(vcpu);
 	kvm_timer_vcpu_load(vcpu);
 	if (has_vhe())
 		kvm_vcpu_load_sysregs_vhe(vcpu);
@@ -346,7 +346,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 	if (has_vhe())
 		kvm_vcpu_put_sysregs_vhe(vcpu);
 	kvm_timer_vcpu_put(vcpu);
-	kvm_vgic_put(vcpu);
+	kvm_irqchip_vcpu_put(vcpu);
 	kvm_vcpu_pmu_restore_host(vcpu);
 
 	vcpu->cpu = -1;
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index b519fb56a8cd..24b3ed9bae5d 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -20,6 +20,8 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_vcpu_init		= kvm_vgic_vcpu_init,
 	.irqchip_vcpu_blocking		= kvm_vgic_vcpu_blocking,
 	.irqchip_vcpu_unblocking	= kvm_vgic_vcpu_unblocking,
+	.irqchip_vcpu_load		= kvm_vgic_load,
+	.irqchip_vcpu_put		= kvm_vgic_put,
 };
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index d8a0e3729de4..190737402365 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -321,4 +321,7 @@ int vgic_v4_init(struct kvm *kvm);
 void vgic_v4_teardown(struct kvm *kvm);
 void vgic_v4_configure_vsgis(struct kvm *kvm);
 
+void kvm_vgic_load(struct kvm_vcpu *vcpu);
+void kvm_vgic_put(struct kvm_vcpu *vcpu);
+
 #endif
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 2bffc2d513ef..a06d9483e3a6 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -349,9 +349,6 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
-void kvm_vgic_load(struct kvm_vcpu *vcpu);
-void kvm_vgic_put(struct kvm_vcpu *vcpu);
-
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 12/23] KVM: arm64: Move kvm_vgic_vcpu_pending_irq() to irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (10 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 11/23] KVM: arm64: Move kvm_vgic_vcpu_load/put() " Marc Zyngier
@ 2020-09-03 15:25 ` Marc Zyngier
  2020-09-04 14:57   ` Jonathan Cameron
  2020-09-03 15:26 ` [PATCH 13/23] KVM: arm64: Move vgic resource mapping on first run " Marc Zyngier
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:25 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Abstract the calls to kvm_vgic_vcpu_pending_irq() via the irqchip_flow
structure.

No functional change.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h | 4 ++++
 arch/arm64/kvm/arm.c             | 4 ++--
 arch/arm64/kvm/vgic/vgic-init.c  | 1 +
 arch/arm64/kvm/vgic/vgic.h       | 6 ++++++
 include/kvm/arm_vgic.h           | 3 ---
 5 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 50dfd641cd67..e7a244176ade 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -24,6 +24,7 @@ struct kvm_irqchip_flow {
 	void (*irqchip_vcpu_unblocking)(struct kvm_vcpu *);
 	void (*irqchip_vcpu_load)(struct kvm_vcpu *);
 	void (*irqchip_vcpu_put)(struct kvm_vcpu *);
+	int  (*irqchip_vcpu_pending_irq)(struct kvm_vcpu *);
 };
 
 /*
@@ -70,4 +71,7 @@ struct kvm_irqchip_flow {
 #define kvm_irqchip_vcpu_put(v)				\
 	__vcpu_irqchip_action((v), vcpu_put, (v))
 
+#define kvm_irqchip_vcpu_pending_irq(v)			\
+	__vcpu_irqchip_action_ret((v), vcpu_pending_irq, (v))
+
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 84d48c312b84..3496d200e488 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -399,8 +399,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
 	bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF);
-	return ((irq_lines || kvm_vgic_vcpu_pending_irq(v))
-		&& !v->arch.power_off && !v->arch.pause);
+	return ((irq_lines || kvm_irqchip_vcpu_pending_irq(v)) &&
+		!v->arch.power_off && !v->arch.pause);
 }
 
 bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 24b3ed9bae5d..8bb847045ef9 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -22,6 +22,7 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_vcpu_unblocking	= kvm_vgic_vcpu_unblocking,
 	.irqchip_vcpu_load		= kvm_vgic_load,
 	.irqchip_vcpu_put		= kvm_vgic_put,
+	.irqchip_vcpu_pending_irq	= kvm_vgic_vcpu_pending_irq,
 };
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 190737402365..c5511823eec5 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -321,7 +321,13 @@ int vgic_v4_init(struct kvm *kvm);
 void vgic_v4_teardown(struct kvm *kvm);
 void vgic_v4_configure_vsgis(struct kvm *kvm);
 
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
+
 void kvm_vgic_load(struct kvm_vcpu *vcpu);
 void kvm_vgic_put(struct kvm_vcpu *vcpu);
 
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
+
+
 #endif
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index a06d9483e3a6..b2adf9cca334 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -347,14 +347,11 @@ int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
 
-int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
-
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
 
-bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
 void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid);
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 13/23] KVM: arm64: Move vgic resource mapping on first run to irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (11 preceding siblings ...)
  2020-09-03 15:25 ` [PATCH 12/23] KVM: arm64: Move kvm_vgic_vcpu_pending_irq() " Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-03 15:26 ` [PATCH 14/23] KVM: arm64: Move kvm_vgic_vcpu_{sync, flush}_hwstate() " Marc Zyngier
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

The "first run" part of the vgic init is pretty cumbersome, as
it leaks all over the place. Reduce its footprint by moving it
to an actual per-vcpu "first run" callback, and let it deal
with the resource mapping.

This allows the vgic_ready() macro to be made vgic-private,
and placed in the common vgic code instead of the architecture
backends.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h |  4 ++++
 arch/arm64/kvm/arm.c             | 12 +++---------
 arch/arm64/kvm/vgic/vgic-init.c  | 13 ++++++++++---
 arch/arm64/kvm/vgic/vgic-v2.c    |  5 -----
 arch/arm64/kvm/vgic/vgic-v3.c    |  4 ----
 arch/arm64/kvm/vgic/vgic.h       |  2 ++
 include/kvm/arm_vgic.h           |  2 --
 7 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index e7a244176ade..7d888f10aabe 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -25,6 +25,7 @@ struct kvm_irqchip_flow {
 	void (*irqchip_vcpu_load)(struct kvm_vcpu *);
 	void (*irqchip_vcpu_put)(struct kvm_vcpu *);
 	int  (*irqchip_vcpu_pending_irq)(struct kvm_vcpu *);
+	int  (*irqchip_vcpu_first_run)(struct kvm_vcpu *);
 };
 
 /*
@@ -74,4 +75,7 @@ struct kvm_irqchip_flow {
 #define kvm_irqchip_vcpu_pending_irq(v)			\
 	__vcpu_irqchip_action_ret((v), vcpu_pending_irq, (v))
 
+#define kvm_irqchip_vcpu_first_run(v)			\
+	__vcpu_irqchip_action_ret((v), vcpu_first_run, (v))
+
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 3496d200e488..0db71d2a38a4 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -503,15 +503,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
 	vcpu->arch.has_run_once = true;
 
 	if (likely(irqchip_in_kernel(kvm))) {
-		/*
-		 * Map the VGIC hardware resources before running a vcpu the
-		 * first time on this VM.
-		 */
-		if (unlikely(!vgic_ready(kvm))) {
-			ret = kvm_vgic_map_resources(kvm);
-			if (ret)
-				return ret;
-		}
+		ret = kvm_irqchip_vcpu_first_run(vcpu);
+		if (ret)
+			return ret;
 	} else {
 		/*
 		 * Tell the rest of the code that there are userspace irqchip
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 8bb847045ef9..8ec8064467a7 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -12,6 +12,7 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+static int kvm_vgic_vcpu_first_run(struct kvm_vcpu *vcpu);
 static int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
 static void kvm_vgic_destroy(struct kvm *kvm);
 
@@ -23,6 +24,7 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_vcpu_load		= kvm_vgic_load,
 	.irqchip_vcpu_put		= kvm_vgic_put,
 	.irqchip_vcpu_pending_irq	= kvm_vgic_vcpu_pending_irq,
+	.irqchip_vcpu_first_run		= kvm_vgic_vcpu_first_run,
 };
 
 /*
@@ -440,14 +442,17 @@ int vgic_lazy_init(struct kvm *kvm)
  * Also map the virtual CPU interface into the VM.
  * v2/v3 derivatives call vgic_init if not already done.
  * vgic_ready() returns true if this function has succeeded.
- * @kvm: kvm struct pointer
+ * @vcpu: vcpu struct pointer
  */
-int kvm_vgic_map_resources(struct kvm *kvm)
+static int kvm_vgic_vcpu_first_run(struct kvm_vcpu *vcpu)
 {
+	struct kvm *kvm = vcpu->kvm;
+	struct vgic_dist *dist = &kvm->arch.vgic;
 	int ret = 0;
 
 	mutex_lock(&kvm->lock);
-	if (!irqchip_in_kernel(kvm))
+
+	if (vgic_ready(kvm))
 		goto out;
 
 	if (irqchip_is_gic_v2(kvm))
@@ -457,6 +462,8 @@ int kvm_vgic_map_resources(struct kvm *kvm)
 
 	if (ret)
 		__kvm_vgic_destroy(kvm);
+	else
+		dist->ready = true;
 
 out:
 	mutex_unlock(&kvm->lock);
diff --git a/arch/arm64/kvm/vgic/vgic-v2.c b/arch/arm64/kvm/vgic/vgic-v2.c
index ebf53a4e1296..a6aaffd2124f 100644
--- a/arch/arm64/kvm/vgic/vgic-v2.c
+++ b/arch/arm64/kvm/vgic/vgic-v2.c
@@ -306,9 +306,6 @@ int vgic_v2_map_resources(struct kvm *kvm)
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	int ret = 0;
 
-	if (vgic_ready(kvm))
-		goto out;
-
 	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
 	    IS_VGIC_ADDR_UNDEF(dist->vgic_cpu_base)) {
 		kvm_err("Need to set vgic cpu and dist addresses first\n");
@@ -348,8 +345,6 @@ int vgic_v2_map_resources(struct kvm *kvm)
 		}
 	}
 
-	dist->ready = true;
-
 out:
 	return ret;
 }
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index c6fdb1222453..d176ad9bab85 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -496,9 +496,6 @@ int vgic_v3_map_resources(struct kvm *kvm)
 	int ret = 0;
 	int c;
 
-	if (vgic_ready(kvm))
-		goto out;
-
 	kvm_for_each_vcpu(c, vcpu, kvm) {
 		struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 
@@ -538,7 +535,6 @@ int vgic_v3_map_resources(struct kvm *kvm)
 
 	if (kvm_vgic_global_state.has_gicv4_1)
 		vgic_v4_configure_vsgis(kvm);
-	dist->ready = true;
 
 out:
 	return ret;
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index c5511823eec5..48e9efda9d8b 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -98,6 +98,8 @@
 #define DEBUG_SPINLOCK_BUG_ON(p)
 #endif
 
+#define vgic_ready(k)		((k)->arch.vgic.ready)
+
 /* Requires the irq_lock to be held by the caller. */
 static inline bool irq_is_pending(struct vgic_irq *irq)
 {
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index b2adf9cca334..fad523007e2b 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -336,7 +336,6 @@ extern struct static_key_false vgic_v3_cpuif_trap;
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
-int kvm_vgic_map_resources(struct kvm *kvm);
 int kvm_vgic_hyp_init(void);
 void kvm_vgic_init_cpu_hardware(void);
 
@@ -348,7 +347,6 @@ int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
 
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
-#define vgic_ready(k)		((k)->arch.vgic.ready)
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
 
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 14/23] KVM: arm64: Move kvm_vgic_vcpu_{sync, flush}_hwstate() to irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (12 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 13/23] KVM: arm64: Move vgic resource mapping on first run " Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-03 15:26 ` [PATCH 15/23] KVM: arm64: nVHE: Only save/restore GICv3 state if modeling a GIC Marc Zyngier
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Abstract the calls to kvm_vgic_vcpu_({sync,flush}_hwstate) via the
irqchip_flow structure.

No functional change.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h | 8 ++++++++
 arch/arm64/kvm/arm.c             | 6 +++---
 arch/arm64/kvm/vgic/vgic-init.c  | 2 ++
 include/kvm/arm_vgic.h           | 2 --
 4 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 7d888f10aabe..92aaec05ee75 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -26,6 +26,8 @@ struct kvm_irqchip_flow {
 	void (*irqchip_vcpu_put)(struct kvm_vcpu *);
 	int  (*irqchip_vcpu_pending_irq)(struct kvm_vcpu *);
 	int  (*irqchip_vcpu_first_run)(struct kvm_vcpu *);
+	void (*irqchip_vcpu_flush_hwstate)(struct kvm_vcpu *);
+	void (*irqchip_vcpu_sync_hwstate)(struct kvm_vcpu *);
 };
 
 /*
@@ -78,4 +80,10 @@ struct kvm_irqchip_flow {
 #define kvm_irqchip_vcpu_first_run(v)			\
 	__vcpu_irqchip_action_ret((v), vcpu_first_run, (v))
 
+#define kvm_irqchip_vcpu_flush_hwstate(v)		\
+	__vcpu_irqchip_action((v), vcpu_flush_hwstate, (v))
+
+#define kvm_irqchip_vcpu_sync_hwstate(v)		\
+	__vcpu_irqchip_action((v), vcpu_sync_hwstate, (v))
+
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 0db71d2a38a4..875e68514661 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -661,7 +661,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
 		local_irq_disable();
 
-		kvm_vgic_flush_hwstate(vcpu);
+		kvm_irqchip_vcpu_flush_hwstate(vcpu);
 
 		/*
 		 * Exit if we have a signal pending so that we can deliver the
@@ -702,7 +702,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 			kvm_pmu_sync_hwstate(vcpu);
 			if (static_branch_unlikely(&userspace_irqchip_in_use))
 				kvm_timer_sync_user(vcpu);
-			kvm_vgic_sync_hwstate(vcpu);
+			kvm_irqchip_vcpu_sync_hwstate(vcpu);
 			local_irq_enable();
 			preempt_enable();
 			continue;
@@ -738,7 +738,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 		 * the timer code needs to know if the virtual timer
 		 * interrupts are active.
 		 */
-		kvm_vgic_sync_hwstate(vcpu);
+		kvm_irqchip_vcpu_sync_hwstate(vcpu);
 
 		/*
 		 * Sync the timer hardware state before enabling interrupts as
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 8ec8064467a7..53fadbf4ca89 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -25,6 +25,8 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_vcpu_put		= kvm_vgic_put,
 	.irqchip_vcpu_pending_irq	= kvm_vgic_vcpu_pending_irq,
 	.irqchip_vcpu_first_run		= kvm_vgic_vcpu_first_run,
+	.irqchip_vcpu_flush_hwstate	= kvm_vgic_flush_hwstate,
+	.irqchip_vcpu_sync_hwstate	= kvm_vgic_sync_hwstate,
 };
 
 /*
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index fad523007e2b..4b3a334185fa 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -350,8 +350,6 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
 
-void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
-void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
 void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid);
 
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg, bool allow_group1);
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 15/23] KVM: arm64: nVHE: Only save/restore GICv3 state if modeling a GIC
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (13 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 14/23] KVM: arm64: Move kvm_vgic_vcpu_{sync, flush}_hwstate() " Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-03 15:26 ` [PATCH 16/23] KVM: arm64: Move interrupt injection to irqchip_flow Marc Zyngier
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

If we aren't modeling a GIC, there is no need to save/restore
the GICv3 state at all. Note that this only matters for nVHE,
as VHE already has this code outside of the world switch.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/hyp/nvhe/switch.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index 0970442d2dbc..be77eb156542 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -101,16 +101,22 @@ static void __deactivate_vm(struct kvm_vcpu *vcpu)
 /* Save VGICv3 state on non-VHE systems */
 static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
+	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) &&
+	    (irqchip_is_gic_v2(kvm) || irqchip_is_gic_v3(kvm))) {
 		__vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
 		__vgic_v3_deactivate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
 	}
 }
 
-/* Restore VGICv3 state on non_VEH systems */
+/* Restore VGICv3 state on non-VHE systems */
 static void __hyp_vgic_restore_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
+	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) &&
+	    (irqchip_is_gic_v2(kvm) || irqchip_is_gic_v3(kvm))) {
 		__vgic_v3_activate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
 		__vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
 	}
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 16/23] KVM: arm64: Move interrupt injection to irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (14 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 15/23] KVM: arm64: nVHE: Only save/restore GICv3 state if modeling a GIC Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-03 15:26 ` [PATCH 17/23] KVM: arm64: Move mapping of HW interrupts into irqchip_flow Marc Zyngier
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

As we continue abstracting away the VGIC, let's make a small
change while we're at it: Let's offer two callbacks for "wired"
interrupt injection:

- Interrupts generated from the kernel itself
- Interrupts generated by userspace via the KVM_IRQ_LINE ioctl

The various checks are pushed into the vgic code. MSI injection,
such as the one used by userspace to tickle the ITS are left alone
for now.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h | 11 +++++++++++
 arch/arm64/kvm/arch_timer.c      |  8 ++++----
 arch/arm64/kvm/arm.c             | 12 ++++--------
 arch/arm64/kvm/pmu-emul.c        |  4 ++--
 arch/arm64/kvm/vgic/vgic-init.c  |  2 ++
 arch/arm64/kvm/vgic/vgic.c       | 20 +++++++++++++++++++-
 arch/arm64/kvm/vgic/vgic.h       |  6 ++++++
 include/kvm/arm_vgic.h           |  2 --
 8 files changed, 48 insertions(+), 17 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 92aaec05ee75..f816d4814fcf 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -28,6 +28,11 @@ struct kvm_irqchip_flow {
 	int  (*irqchip_vcpu_first_run)(struct kvm_vcpu *);
 	void (*irqchip_vcpu_flush_hwstate)(struct kvm_vcpu *);
 	void (*irqchip_vcpu_sync_hwstate)(struct kvm_vcpu *);
+	int  (*irqchip_inject_irq)(struct kvm *, unsigned int cpu,
+				   unsigned int intid, bool, void *);
+	int  (*irqchip_inject_userspace_irq)(struct kvm *, unsigned int type,
+					     unsigned int cpu,
+					     unsigned int intid, bool);
 };
 
 /*
@@ -86,4 +91,10 @@ struct kvm_irqchip_flow {
 #define kvm_irqchip_vcpu_sync_hwstate(v)		\
 	__vcpu_irqchip_action((v), vcpu_sync_hwstate, (v))
 
+#define kvm_irqchip_inject_irq(k, ...)			\
+	__kvm_irqchip_action_ret((k), inject_irq, (k), __VA_ARGS__)
+
+#define kvm_irqchip_inject_userspace_irq(k, ...)	\
+	__kvm_irqchip_action_ret((k), inject_userspace_irq, (k), __VA_ARGS__)
+
 #endif
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 32ba6fbc3814..397bd7aea1f5 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -388,10 +388,10 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 				   timer_ctx->irq.level);
 
 	if (!userspace_irqchip(vcpu->kvm)) {
-		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
-					  timer_ctx->irq.irq,
-					  timer_ctx->irq.level,
-					  timer_ctx);
+		ret = kvm_irqchip_inject_irq(vcpu->kvm, vcpu->vcpu_id,
+					     timer_ctx->irq.irq,
+					     timer_ctx->irq.level,
+					     timer_ctx);
 		WARN_ON(ret);
 	}
 }
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 875e68514661..139f4154038b 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -870,18 +870,14 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
 		if (!vcpu)
 			return -EINVAL;
 
-		if (irq_num < VGIC_NR_SGIS || irq_num >= VGIC_NR_PRIVATE_IRQS)
-			return -EINVAL;
-
-		return kvm_vgic_inject_irq(kvm, vcpu->vcpu_id, irq_num, level, NULL);
+		return kvm_irqchip_inject_userspace_irq(kvm, irq_type, vcpu_idx,
+							irq_num, level);
 	case KVM_ARM_IRQ_TYPE_SPI:
 		if (!irqchip_in_kernel(kvm))
 			return -ENXIO;
 
-		if (irq_num < VGIC_NR_PRIVATE_IRQS)
-			return -EINVAL;
-
-		return kvm_vgic_inject_irq(kvm, 0, irq_num, level, NULL);
+		return kvm_irqchip_inject_userspace_irq(kvm, irq_type, 0,
+							irq_num, level);
 	}
 
 	return -EINVAL;
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index f0d0312c0a55..f31ee6ad3444 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -378,8 +378,8 @@ static void kvm_pmu_update_state(struct kvm_vcpu *vcpu)
 	pmu->irq_level = overflow;
 
 	if (likely(irqchip_in_kernel(vcpu->kvm))) {
-		int ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
-					      pmu->irq_num, overflow, pmu);
+		int ret = kvm_irqchip_inject_irq(vcpu->kvm, vcpu->vcpu_id,
+						 pmu->irq_num, overflow, pmu);
 		WARN_ON(ret);
 	}
 }
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 53fadbf4ca89..7a8504a5b634 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -27,6 +27,8 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_vcpu_first_run		= kvm_vgic_vcpu_first_run,
 	.irqchip_vcpu_flush_hwstate	= kvm_vgic_flush_hwstate,
 	.irqchip_vcpu_sync_hwstate	= kvm_vgic_sync_hwstate,
+	.irqchip_inject_irq		= kvm_vgic_inject_irq,
+	.irqchip_inject_userspace_irq	= kvm_vgic_inject_userspace_irq,
 };
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index f576273c5608..d676c010e45f 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -434,7 +434,7 @@ bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
  * level-sensitive interrupts.  You can think of the level parameter as 1
  * being HIGH and 0 being LOW and all devices being active-HIGH.
  */
-int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+int kvm_vgic_inject_irq(struct kvm *kvm, unsigned int cpuid, unsigned int intid,
 			bool level, void *owner)
 {
 	struct kvm_vcpu *vcpu;
@@ -476,6 +476,24 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 	return 0;
 }
 
+int kvm_vgic_inject_userspace_irq(struct kvm *kvm, unsigned int type,
+				  unsigned int cpuid, unsigned int intid,
+				  bool level)
+{
+	switch (type) {
+	case KVM_ARM_IRQ_TYPE_PPI:
+		if (intid < VGIC_NR_SGIS || intid >= VGIC_NR_PRIVATE_IRQS)
+			return -EINVAL;
+		return kvm_vgic_inject_irq(kvm, cpuid, intid, level, NULL);
+	case KVM_ARM_IRQ_TYPE_SPI:
+		if (intid < VGIC_NR_PRIVATE_IRQS)
+			return -EINVAL;
+		return kvm_vgic_inject_irq(kvm, 0, intid, level, NULL);
+	default:
+		return -EINVAL;
+	}
+}
+
 /* @irq->irq_lock must be held */
 static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 			    unsigned int host_irq,
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 48e9efda9d8b..cddbd9b951e4 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -232,6 +232,12 @@ void vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu);
 void kvm_vgic_vcpu_blocking(struct kvm_vcpu *vcpu);
 void kvm_vgic_vcpu_unblocking(struct kvm_vcpu *vcpu);
 
+int kvm_vgic_inject_irq(struct kvm *kvm, unsigned int cpuid, unsigned int intid,
+			bool level, void *owner);
+int kvm_vgic_inject_userspace_irq(struct kvm *kvm, unsigned int type,
+				  unsigned int cpuid, unsigned int intid,
+				  bool level);
+
 bool vgic_has_its(struct kvm *kvm);
 int kvm_vgic_register_its_device(void);
 void vgic_enable_lpis(struct kvm_vcpu *vcpu);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 4b3a334185fa..fba68129337d 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -339,8 +339,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
 int kvm_vgic_hyp_init(void);
 void kvm_vgic_init_cpu_hardware(void);
 
-int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
-			bool level, void *owner);
 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
 			  u32 vintid, bool (*get_input_level)(int vindid));
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 17/23] KVM: arm64: Move mapping of HW interrupts into irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (15 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 16/23] KVM: arm64: Move interrupt injection to irqchip_flow Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-03 15:26 ` [PATCH 18/23] KVM: arm64: Move set_owner " Marc Zyngier
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

As we continue cutting a VGIC-shaped hole in KVM, let's indirect
all of the handling of mapped interrupts into the bit irqchip_flow
bucket.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h | 17 +++++++++++++++++
 arch/arm64/kvm/arch_timer.c      | 22 +++++++++++-----------
 arch/arm64/kvm/vgic/vgic-init.c  |  4 ++++
 arch/arm64/kvm/vgic/vgic.h       |  6 ++++++
 include/kvm/arm_vgic.h           |  7 -------
 5 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index f816d4814fcf..16556417bd4a 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -33,6 +33,11 @@ struct kvm_irqchip_flow {
 	int  (*irqchip_inject_userspace_irq)(struct kvm *, unsigned int type,
 					     unsigned int cpu,
 					     unsigned int intid, bool);
+	bool (*irqchip_map_is_active)(struct kvm_vcpu *, unsigned in);
+	void (*irqchip_reset_mapped_irq)(struct kvm_vcpu *, u32);
+	int  (*irqchip_map_phys_irq)(struct kvm_vcpu *, unsigned int,
+				     u32, bool (*)(int));
+	int  (*irqchip_unmap_phys_irq)(struct kvm_vcpu *, unsigned int);
 };
 
 /*
@@ -97,4 +102,16 @@ struct kvm_irqchip_flow {
 #define kvm_irqchip_inject_userspace_irq(k, ...)	\
 	__kvm_irqchip_action_ret((k), inject_userspace_irq, (k), __VA_ARGS__)
 
+#define kvm_irqchip_map_is_active(v, ...)		\
+	__vcpu_irqchip_action_ret((v), map_is_active, (v), __VA_ARGS__)
+
+#define kvm_irqchip_reset_mapped_irq(v, ...)		\
+	__vcpu_irqchip_action((v), reset_mapped_irq, (v), __VA_ARGS__)
+
+#define kvm_irqchip_map_phys_irq(v, ...)		\
+	__vcpu_irqchip_action_ret((v), map_phys_irq, (v), __VA_ARGS__)
+
+#define kvm_irqchip_unmap_phys_irq(v, ...)		\
+	__vcpu_irqchip_action_ret((v), unmap_phys_irq, (v), __VA_ARGS__)
+
 #endif
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 397bd7aea1f5..16999de299a7 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -562,7 +562,7 @@ static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
 	kvm_timer_update_irq(ctx->vcpu, kvm_timer_should_fire(ctx), ctx);
 
 	if (irqchip_in_kernel(vcpu->kvm))
-		phys_active = kvm_vgic_map_is_active(vcpu, ctx->irq.irq);
+		phys_active = kvm_irqchip_map_is_active(vcpu, ctx->irq.irq);
 
 	phys_active |= ctx->irq.level;
 
@@ -734,9 +734,9 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
 		kvm_timer_update_irq(vcpu, false, vcpu_ptimer(vcpu));
 
 		if (irqchip_in_kernel(vcpu->kvm)) {
-			kvm_vgic_reset_mapped_irq(vcpu, map.direct_vtimer->irq.irq);
+			kvm_irqchip_reset_mapped_irq(vcpu, map.direct_vtimer->irq.irq);
 			if (map.direct_ptimer)
-				kvm_vgic_reset_mapped_irq(vcpu, map.direct_ptimer->irq.irq);
+				kvm_irqchip_reset_mapped_irq(vcpu, map.direct_ptimer->irq.irq);
 		}
 	}
 
@@ -1139,18 +1139,18 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 
 	get_timer_map(vcpu, &map);
 
-	ret = kvm_vgic_map_phys_irq(vcpu,
-				    map.direct_vtimer->host_timer_irq,
-				    map.direct_vtimer->irq.irq,
-				    kvm_arch_timer_get_input_level);
+	ret = kvm_irqchip_map_phys_irq(vcpu,
+				       map.direct_vtimer->host_timer_irq,
+				       map.direct_vtimer->irq.irq,
+				       kvm_arch_timer_get_input_level);
 	if (ret)
 		return ret;
 
 	if (map.direct_ptimer) {
-		ret = kvm_vgic_map_phys_irq(vcpu,
-					    map.direct_ptimer->host_timer_irq,
-					    map.direct_ptimer->irq.irq,
-					    kvm_arch_timer_get_input_level);
+		ret = kvm_irqchip_map_phys_irq(vcpu,
+					       map.direct_ptimer->host_timer_irq,
+					       map.direct_ptimer->irq.irq,
+					       kvm_arch_timer_get_input_level);
 	}
 
 	if (ret)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 7a8504a5b634..ed62c0a27b53 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -29,6 +29,10 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_vcpu_sync_hwstate	= kvm_vgic_sync_hwstate,
 	.irqchip_inject_irq		= kvm_vgic_inject_irq,
 	.irqchip_inject_userspace_irq	= kvm_vgic_inject_userspace_irq,
+	.irqchip_map_is_active		= kvm_vgic_map_is_active,
+	.irqchip_reset_mapped_irq	= kvm_vgic_reset_mapped_irq,
+	.irqchip_map_phys_irq		= kvm_vgic_map_phys_irq,
+	.irqchip_unmap_phys_irq		= kvm_vgic_unmap_phys_irq,
 };
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index cddbd9b951e4..af4a0e5f31c1 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -329,6 +329,12 @@ int vgic_v4_init(struct kvm *kvm);
 void vgic_v4_teardown(struct kvm *kvm);
 void vgic_v4_configure_vsgis(struct kvm *kvm);
 
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
+void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid);
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
+			  u32 vintid, bool (*get_input_level)(int));
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
+
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
 void kvm_vgic_load(struct kvm_vcpu *vcpu);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index fba68129337d..ff8c49c0ebbd 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -339,17 +339,10 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
 int kvm_vgic_hyp_init(void);
 void kvm_vgic_init_cpu_hardware(void);
 
-int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
-			  u32 vintid, bool (*get_input_level)(int vindid));
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
-
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
 
-void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid);
-
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg, bool allow_group1);
 
 /**
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 18/23] KVM: arm64: Move set_owner into irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (16 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 17/23] KVM: arm64: Move mapping of HW interrupts into irqchip_flow Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-03 15:26 ` [PATCH 19/23] KVM: arm64: Turn vgic_initialized into irqchip_finalized Marc Zyngier
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Move the set_owner callback into irqchip_flow. It's not that
useful an API anyway, and we should consider getting rid of it.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h | 4 ++++
 arch/arm64/kvm/arch_timer.c      | 4 ++--
 arch/arm64/kvm/pmu-emul.c        | 4 ++--
 arch/arm64/kvm/vgic/vgic-init.c  | 1 +
 arch/arm64/kvm/vgic/vgic.h       | 1 +
 include/kvm/arm_vgic.h           | 2 --
 6 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 16556417bd4a..d1fc86b54f2d 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -38,6 +38,7 @@ struct kvm_irqchip_flow {
 	int  (*irqchip_map_phys_irq)(struct kvm_vcpu *, unsigned int,
 				     u32, bool (*)(int));
 	int  (*irqchip_unmap_phys_irq)(struct kvm_vcpu *, unsigned int);
+	int  (*irqchip_set_owner)(struct kvm_vcpu *, unsigned int, void *);
 };
 
 /*
@@ -114,4 +115,7 @@ struct kvm_irqchip_flow {
 #define kvm_irqchip_unmap_phys_irq(v, ...)		\
 	__vcpu_irqchip_action_ret((v), unmap_phys_irq, (v), __VA_ARGS__)
 
+#define kvm_irqchip_set_owner(v, ...)		\
+	__vcpu_irqchip_action_ret((v), set_owner, (v), __VA_ARGS__)
+
 #endif
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 16999de299a7..706fd0c63273 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -1083,12 +1083,12 @@ static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu)
 	int i, ret;
 
 	vtimer_irq = vcpu_vtimer(vcpu)->irq.irq;
-	ret = kvm_vgic_set_owner(vcpu, vtimer_irq, vcpu_vtimer(vcpu));
+	ret = kvm_irqchip_set_owner(vcpu, vtimer_irq, vcpu_vtimer(vcpu));
 	if (ret)
 		return false;
 
 	ptimer_irq = vcpu_ptimer(vcpu)->irq.irq;
-	ret = kvm_vgic_set_owner(vcpu, ptimer_irq, vcpu_ptimer(vcpu));
+	ret = kvm_irqchip_set_owner(vcpu, ptimer_irq, vcpu_ptimer(vcpu));
 	if (ret)
 		return false;
 
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index f31ee6ad3444..d87f71845a64 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -758,8 +758,8 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
 		if (!kvm_arm_pmu_irq_initialized(vcpu))
 			return -ENXIO;
 
-		ret = kvm_vgic_set_owner(vcpu, vcpu->arch.pmu.irq_num,
-					 &vcpu->arch.pmu);
+		ret = kvm_irqchip_set_owner(vcpu, vcpu->arch.pmu.irq_num,
+					    &vcpu->arch.pmu);
 		if (ret)
 			return ret;
 	}
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index ed62c0a27b53..6ace624b439d 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -33,6 +33,7 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_reset_mapped_irq	= kvm_vgic_reset_mapped_irq,
 	.irqchip_map_phys_irq		= kvm_vgic_map_phys_irq,
 	.irqchip_unmap_phys_irq		= kvm_vgic_unmap_phys_irq,
+	.irqchip_set_owner		= kvm_vgic_set_owner,
 };
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index af4a0e5f31c1..c9e14a6cddf6 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -334,6 +334,7 @@ void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid);
 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
 			  u32 vintid, bool (*get_input_level)(int));
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
+int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner);
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index ff8c49c0ebbd..f753110e24f9 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -362,8 +362,6 @@ static inline int kvm_vgic_get_max_vcpus(void)
  */
 int kvm_vgic_setup_default_irq_routing(struct kvm *kvm);
 
-int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner);
-
 struct kvm_kernel_irq_routing_entry;
 
 int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int irq,
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 19/23] KVM: arm64: Turn vgic_initialized into irqchip_finalized
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (17 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 18/23] KVM: arm64: Move set_owner " Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-03 15:26 ` [PATCH 20/23] KVM: arm64: Move irqfd routing to irqchip_flow Marc Zyngier
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

As we aim to make the core KVM/arm64 code GIC-agnostic, let's
turn vgic_initialized into something more generic, and move the
corresponding flag outside of the vgic data structure.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_host.h     |  1 +
 arch/arm64/include/asm/kvm_irq.h      |  2 ++
 arch/arm64/kvm/arch_timer.c           |  2 +-
 arch/arm64/kvm/arm.c                  |  4 ++--
 arch/arm64/kvm/pmu-emul.c             |  2 +-
 arch/arm64/kvm/vgic/vgic-debug.c      |  2 +-
 arch/arm64/kvm/vgic/vgic-init.c       | 10 +++++-----
 arch/arm64/kvm/vgic/vgic-irqfd.c      |  2 +-
 arch/arm64/kvm/vgic/vgic-its.c        |  2 +-
 arch/arm64/kvm/vgic/vgic-kvm-device.c |  2 +-
 arch/arm64/kvm/vgic/vgic-v3.c         |  2 +-
 arch/arm64/kvm/vgic/vgic.c            | 10 +++++-----
 include/kvm/arm_vgic.h                |  2 --
 13 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 52b502f3076f..5dd92873d40f 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -100,6 +100,7 @@ struct kvm_arch {
 
 	/* Interrupt controller */
 	enum kvm_irqchip_type	irqchip_type;
+	bool			irqchip_finalized;
 	struct kvm_irqchip_flow	irqchip_flow;
 	struct vgic_dist	vgic;
 
diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index d1fc86b54f2d..649b7d4c7e9f 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -17,6 +17,8 @@ enum kvm_irqchip_type {
 #define irqchip_is_gic_v2(k)	((k)->arch.irqchip_type == IRQCHIP_GICv2)
 #define irqchip_is_gic_v3(k)	((k)->arch.irqchip_type == IRQCHIP_GICv3)
 
+#define irqchip_finalized(k)	((k)->arch.irqchip_finalized)
+
 struct kvm_irqchip_flow {
 	void (*irqchip_destroy)(struct kvm *);
 	int  (*irqchip_vcpu_init)(struct kvm_vcpu *);
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 706fd0c63273..9b84eb145ccd 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -1129,7 +1129,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 	if (!irqchip_in_kernel(vcpu->kvm))
 		goto no_vgic;
 
-	if (!vgic_initialized(vcpu->kvm))
+	if (!irqchip_finalized(vcpu->kvm))
 		return -ENODEV;
 
 	if (!timer_irqs_are_valid(vcpu)) {
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 139f4154038b..678533871cfa 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -235,7 +235,7 @@ void kvm_arch_free_vm(struct kvm *kvm)
 
 int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
 {
-	if (irqchip_in_kernel(kvm) && vgic_initialized(kvm))
+	if (irqchip_in_kernel(kvm) && irqchip_finalized(kvm))
 		return -EBUSY;
 
 	if (id >= kvm->arch.max_vcpus)
@@ -525,7 +525,7 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
 
 bool kvm_arch_intc_initialized(struct kvm *kvm)
 {
-	return vgic_initialized(kvm);
+	return (irqchip_in_kernel(kvm) && irqchip_finalized(kvm));
 }
 
 void kvm_arm_halt_guest(struct kvm *kvm)
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index d87f71845a64..2ab3b5288503 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -752,7 +752,7 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
 		 * implementation, we require the GIC to be already
 		 * initialized when initializing the PMU.
 		 */
-		if (!vgic_initialized(vcpu->kvm))
+		if (!irqchip_finalized(vcpu->kvm))
 			return -ENODEV;
 
 		if (!kvm_arm_pmu_irq_initialized(vcpu))
diff --git a/arch/arm64/kvm/vgic/vgic-debug.c b/arch/arm64/kvm/vgic/vgic-debug.c
index 2d19fd55fc7b..feaccf41e33a 100644
--- a/arch/arm64/kvm/vgic/vgic-debug.c
+++ b/arch/arm64/kvm/vgic/vgic-debug.c
@@ -241,7 +241,7 @@ static int vgic_debug_show(struct seq_file *s, void *v)
 		return 0;
 	}
 
-	if (!kvm->arch.vgic.initialized)
+	if (!irqchip_finalized(kvm))
 		return 0;
 
 	if (iter->vcpu_id < iter->nr_cpus)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 6ace624b439d..a3e0389617a3 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -278,7 +278,7 @@ static void kvm_vgic_vcpu_enable(struct kvm_vcpu *vcpu)
  * - the number of vcpus
  * The function is generally called when nr_spis has been explicitly set
  * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
- * vgic_initialized() returns true when this function has succeeded.
+ * irqchip_finalized() returns true when this function has succeeded.
  * Must be called with kvm->lock held!
  */
 int vgic_init(struct kvm *kvm)
@@ -287,7 +287,7 @@ int vgic_init(struct kvm *kvm)
 	struct kvm_vcpu *vcpu;
 	int ret = 0, i, idx;
 
-	if (vgic_initialized(kvm))
+	if (irqchip_finalized(kvm))
 		return 0;
 
 	/* Are we also in the middle of creating a VCPU? */
@@ -348,7 +348,7 @@ int vgic_init(struct kvm *kvm)
 	vgic_debug_init(kvm);
 
 	dist->implementation_rev = 2;
-	dist->initialized = true;
+	kvm->arch.irqchip_finalized = true;
 
 out:
 	return ret;
@@ -359,8 +359,8 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	struct vgic_redist_region *rdreg, *next;
 
+	kvm->arch.irqchip_finalized = false;
 	dist->ready = false;
-	dist->initialized = false;
 
 	kfree(dist->spis);
 	dist->spis = NULL;
@@ -425,7 +425,7 @@ int vgic_lazy_init(struct kvm *kvm)
 {
 	int ret = 0;
 
-	if (unlikely(!vgic_initialized(kvm))) {
+	if (unlikely(!irqchip_finalized(kvm))) {
 		/*
 		 * We only provide the automatic initialization of the VGIC
 		 * for the legacy case of a GICv2. Any other type must
diff --git a/arch/arm64/kvm/vgic/vgic-irqfd.c b/arch/arm64/kvm/vgic/vgic-irqfd.c
index 79f8899b234c..dbece60c8dc0 100644
--- a/arch/arm64/kvm/vgic/vgic-irqfd.c
+++ b/arch/arm64/kvm/vgic/vgic-irqfd.c
@@ -124,7 +124,7 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
 		 * Injecting SPIs is always possible in atomic context
 		 * as long as the damn vgic is initialized.
 		 */
-		if (unlikely(!vgic_initialized(kvm)))
+		if (unlikely(!irqchip_finalized(kvm)))
 			break;
 		return vgic_irqfd_set_irq(e, kvm, irq_source_id, 1, line_status);
 	}
diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
index 40cbaca81333..5e715f71991d 100644
--- a/arch/arm64/kvm/vgic/vgic-its.c
+++ b/arch/arm64/kvm/vgic/vgic-its.c
@@ -1892,7 +1892,7 @@ static int vgic_its_create(struct kvm_device *dev, u32 type)
 	if (!its)
 		return -ENOMEM;
 
-	if (vgic_initialized(dev->kvm)) {
+	if (irqchip_finalized(dev->kvm)) {
 		int ret = vgic_v4_init(dev->kvm);
 		if (ret < 0) {
 			kfree(its);
diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index 928afb224540..20654f318646 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -532,7 +532,7 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 
 	mutex_lock(&dev->kvm->lock);
 
-	if (unlikely(!vgic_initialized(dev->kvm))) {
+	if (unlikely(!irqchip_finalized(dev->kvm))) {
 		ret = -EBUSY;
 		goto out;
 	}
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index d176ad9bab85..938b73f3f8bf 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -522,7 +522,7 @@ int vgic_v3_map_resources(struct kvm *kvm)
 	 * For a VGICv3 we require the userland to explicitly initialize
 	 * the VGIC before we need to use it.
 	 */
-	if (!vgic_initialized(kvm)) {
+	if (!irqchip_finalized(kvm)) {
 		ret = -EBUSY;
 		goto out;
 	}
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index d676c010e45f..9cbbc24f8a95 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -577,7 +577,7 @@ int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid)
 	struct vgic_irq *irq;
 	unsigned long flags;
 
-	if (!vgic_initialized(vcpu->kvm))
+	if (!irqchip_finalized(vcpu->kvm))
 		return -EAGAIN;
 
 	irq = vgic_get_irq(vcpu->kvm, vcpu, vintid);
@@ -607,7 +607,7 @@ int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner)
 	unsigned long flags;
 	int ret = 0;
 
-	if (!vgic_initialized(vcpu->kvm))
+	if (!irqchip_finalized(vcpu->kvm))
 		return -EAGAIN;
 
 	/* SGIs and LPIs cannot be wired up to any device */
@@ -937,7 +937,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_load(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	if (unlikely(!irqchip_finalized(vcpu->kvm)))
 		return;
 
 	if (kvm_vgic_global_state.type == VGIC_V2)
@@ -948,7 +948,7 @@ void kvm_vgic_load(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_put(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	if (unlikely(!irqchip_finalized(vcpu->kvm)))
 		return;
 
 	if (kvm_vgic_global_state.type == VGIC_V2)
@@ -1044,7 +1044,7 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid)
 	bool map_is_active;
 	unsigned long flags;
 
-	if (!vgic_initialized(vcpu->kvm))
+	if (!irqchip_finalized(vcpu->kvm))
 		return false;
 
 	irq = vgic_get_irq(vcpu->kvm, vcpu, vintid);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index f753110e24f9..cb1f66d373a4 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -202,7 +202,6 @@ struct vgic_redist_region {
 
 struct vgic_dist {
 	bool			ready;
-	bool			initialized;
 
 	/* Implementation revision as reported in the GICD_IIDR */
 	u32			implementation_rev;
@@ -339,7 +338,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
 int kvm_vgic_hyp_init(void);
 void kvm_vgic_init_cpu_hardware(void);
 
-#define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
 
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 20/23] KVM: arm64: Move irqfd routing to irqchip_flow
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (18 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 19/23] KVM: arm64: Turn vgic_initialized into irqchip_finalized Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-03 15:26 ` [PATCH 21/23] KVM: arm64: Tighten msis_require_devid reporting Marc Zyngier
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

irqfd handling is still hidden away in the vgic code. Let's
extract it and move the generic part in the non-GIC code,
with the now required abstraction in the irqchip_flow struct.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_irq.h | 11 +++++
 arch/arm64/kvm/arm.c             | 68 ++++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic-init.c  |  3 ++
 arch/arm64/kvm/vgic/vgic-irqfd.c | 72 ++++++--------------------------
 arch/arm64/kvm/vgic/vgic.h       | 10 +++++
 5 files changed, 104 insertions(+), 60 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 649b7d4c7e9f..05fbe5241642 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -19,6 +19,8 @@ enum kvm_irqchip_type {
 
 #define irqchip_finalized(k)	((k)->arch.irqchip_finalized)
 
+struct kvm_kernel_irq_routing_entry;
+
 struct kvm_irqchip_flow {
 	void (*irqchip_destroy)(struct kvm *);
 	int  (*irqchip_vcpu_init)(struct kvm_vcpu *);
@@ -41,6 +43,15 @@ struct kvm_irqchip_flow {
 				     u32, bool (*)(int));
 	int  (*irqchip_unmap_phys_irq)(struct kvm_vcpu *, unsigned int);
 	int  (*irqchip_set_owner)(struct kvm_vcpu *, unsigned int, void *);
+	int  (*irqchip_irqfd_set_irq)(struct kvm_kernel_irq_routing_entry *e,
+				      struct kvm *kvm, int irq_source_id,
+				      int level, bool line_status);
+	int  (*irqchip_set_msi)(struct kvm_kernel_irq_routing_entry *e,
+				struct kvm *kvm, int irq_source_id,
+				int level, bool line_status);
+	int  (*irqchip_set_irq_inatomic)(struct kvm_kernel_irq_routing_entry *e,
+					 struct kvm *kvm, int irq_source_id,
+					 int level, bool line_status);
 };
 
 /*
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 678533871cfa..d625904633c0 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1592,6 +1592,74 @@ void kvm_arch_irq_bypass_start(struct irq_bypass_consumer *cons)
 	kvm_arm_resume_guest(irqfd->kvm);
 }
 
+/**
+ * kvm_set_routing_entry: populate a kvm routing entry
+ * from a user routing entry
+ *
+ * @kvm: the VM this entry is applied to
+ * @e: kvm kernel routing entry handle
+ * @ue: user api routing entry handle
+ * return 0 on success, -EINVAL on errors.
+ */
+int kvm_set_routing_entry(struct kvm *kvm,
+			  struct kvm_kernel_irq_routing_entry *e,
+			  const struct kvm_irq_routing_entry *ue)
+{
+	int r = -EINVAL;
+
+	switch (ue->type) {
+	case KVM_IRQ_ROUTING_IRQCHIP:
+		e->set = kvm->arch.irqchip_flow.irqchip_irqfd_set_irq;
+		e->irqchip.irqchip = ue->u.irqchip.irqchip;
+		e->irqchip.pin = ue->u.irqchip.pin;
+		if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||
+		    (e->irqchip.irqchip >= KVM_NR_IRQCHIPS))
+			goto out;
+		break;
+	case KVM_IRQ_ROUTING_MSI:
+		e->set = kvm->arch.irqchip_flow.irqchip_set_msi;
+		e->msi.address_lo = ue->u.msi.address_lo;
+		e->msi.address_hi = ue->u.msi.address_hi;
+		e->msi.data = ue->u.msi.data;
+		e->msi.flags = ue->flags;
+		e->msi.devid = ue->u.msi.devid;
+		break;
+	default:
+		goto out;
+	}
+
+	if (!e->set)
+		goto out;
+
+	r = 0;
+out:
+	return r;
+}
+
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+		struct kvm *kvm, int irq_source_id,
+		int level, bool line_status)
+{
+	if (!kvm->arch.irqchip_flow.irqchip_set_msi)
+		return -ENODEV;
+	return kvm->arch.irqchip_flow.irqchip_set_msi(e, kvm, irq_source_id,
+						      level, line_status);
+}
+
+int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
+			      struct kvm *kvm, int irq_source_id, int level,
+			      bool line_status)
+{
+	if (!level || !irqchip_finalized(kvm) ||
+	    !kvm->arch.irqchip_flow.irqchip_set_irq_inatomic)
+		return -EWOULDBLOCK;
+
+	return kvm->arch.irqchip_flow.irqchip_set_irq_inatomic(e, kvm,
+							       irq_source_id,
+							       level,
+							       line_status);
+}
+
 /**
  * Initialize Hyp-mode and memory mappings on all CPUs.
  */
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index a3e0389617a3..440b8c09c030 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -34,6 +34,9 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
 	.irqchip_map_phys_irq		= kvm_vgic_map_phys_irq,
 	.irqchip_unmap_phys_irq		= kvm_vgic_unmap_phys_irq,
 	.irqchip_set_owner		= kvm_vgic_set_owner,
+	.irqchip_irqfd_set_irq		= vgic_irqfd_set_irq,
+	.irqchip_set_msi		= vgic_set_msi,
+	.irqchip_set_irq_inatomic	= vgic_set_irq_inatomic,
 };
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic-irqfd.c b/arch/arm64/kvm/vgic/vgic-irqfd.c
index dbece60c8dc0..5bbdfe982a00 100644
--- a/arch/arm64/kvm/vgic/vgic-irqfd.c
+++ b/arch/arm64/kvm/vgic/vgic-irqfd.c
@@ -15,9 +15,9 @@
  *
  * This is the entry point for irqfd IRQ injection
  */
-static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
-			struct kvm *kvm, int irq_source_id,
-			int level, bool line_status)
+int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
+		       struct kvm *kvm, int irq_source_id,
+		       int level, bool line_status)
 {
 	unsigned int spi_id = e->irqchip.pin + VGIC_NR_PRIVATE_IRQS;
 
@@ -26,46 +26,6 @@ static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
 	return kvm_vgic_inject_irq(kvm, 0, spi_id, level, NULL);
 }
 
-/**
- * kvm_set_routing_entry: populate a kvm routing entry
- * from a user routing entry
- *
- * @kvm: the VM this entry is applied to
- * @e: kvm kernel routing entry handle
- * @ue: user api routing entry handle
- * return 0 on success, -EINVAL on errors.
- */
-int kvm_set_routing_entry(struct kvm *kvm,
-			  struct kvm_kernel_irq_routing_entry *e,
-			  const struct kvm_irq_routing_entry *ue)
-{
-	int r = -EINVAL;
-
-	switch (ue->type) {
-	case KVM_IRQ_ROUTING_IRQCHIP:
-		e->set = vgic_irqfd_set_irq;
-		e->irqchip.irqchip = ue->u.irqchip.irqchip;
-		e->irqchip.pin = ue->u.irqchip.pin;
-		if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||
-		    (e->irqchip.irqchip >= KVM_NR_IRQCHIPS))
-			goto out;
-		break;
-	case KVM_IRQ_ROUTING_MSI:
-		e->set = kvm_set_msi;
-		e->msi.address_lo = ue->u.msi.address_lo;
-		e->msi.address_hi = ue->u.msi.address_hi;
-		e->msi.data = ue->u.msi.data;
-		e->msi.flags = ue->flags;
-		e->msi.devid = ue->u.msi.devid;
-		break;
-	default:
-		goto out;
-	}
-	r = 0;
-out:
-	return r;
-}
-
 static void kvm_populate_msi(struct kvm_kernel_irq_routing_entry *e,
 			     struct kvm_msi *msi)
 {
@@ -75,16 +35,17 @@ static void kvm_populate_msi(struct kvm_kernel_irq_routing_entry *e,
 	msi->flags = e->msi.flags;
 	msi->devid = e->msi.devid;
 }
+
 /**
- * kvm_set_msi: inject the MSI corresponding to the
+ * vgic_set_msi: inject the MSI corresponding to the
  * MSI routing entry
  *
  * This is the entry point for irqfd MSI injection
  * and userspace MSI injection.
  */
-int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
-		struct kvm *kvm, int irq_source_id,
-		int level, bool line_status)
+int vgic_set_msi(struct kvm_kernel_irq_routing_entry *e,
+		 struct kvm *kvm, int irq_source_id,
+		 int level, bool line_status)
 {
 	struct kvm_msi msi;
 
@@ -99,15 +60,12 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
 }
 
 /**
- * kvm_arch_set_irq_inatomic: fast-path for irqfd injection
+ * vgic_set_irq_inatomic: fast-path for irqfd injection
  */
-int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
-			      struct kvm *kvm, int irq_source_id, int level,
-			      bool line_status)
+int vgic_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
+			  struct kvm *kvm, int irq_source_id, int level,
+			  bool line_status)
 {
-	if (!level)
-		return -EWOULDBLOCK;
-
 	switch (e->type) {
 	case KVM_IRQ_ROUTING_MSI: {
 		struct kvm_msi msi;
@@ -120,12 +78,6 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
 	}
 
 	case KVM_IRQ_ROUTING_IRQCHIP:
-		/*
-		 * Injecting SPIs is always possible in atomic context
-		 * as long as the damn vgic is initialized.
-		 */
-		if (unlikely(!irqchip_finalized(kvm)))
-			break;
 		return vgic_irqfd_set_irq(e, kvm, irq_source_id, 1, line_status);
 	}
 
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index c9e14a6cddf6..db3b111ed611 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -324,6 +324,16 @@ void vgic_lpi_translation_cache_init(struct kvm *kvm);
 void vgic_lpi_translation_cache_destroy(struct kvm *kvm);
 void vgic_its_invalidate_cache(struct kvm *kvm);
 
+int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
+		       struct kvm *kvm, int irq_source_id,
+		       int level, bool line_status);
+int vgic_set_msi(struct kvm_kernel_irq_routing_entry *e,
+		 struct kvm *kvm, int irq_source_id,
+		 int level, bool line_status);
+int vgic_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
+			  struct kvm *kvm, int irq_source_id, int level,
+			  bool line_status);
+
 bool vgic_supports_direct_msis(struct kvm *kvm);
 int vgic_v4_init(struct kvm *kvm);
 void vgic_v4_teardown(struct kvm *kvm);
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 21/23] KVM: arm64: Tighten msis_require_devid reporting
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (19 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 20/23] KVM: arm64: Move irqfd routing to irqchip_flow Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-03 15:26 ` [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation Marc Zyngier
  2020-09-03 15:26 ` [PATCH 23/23] KVM: arm64: Add debugfs files for the rVIC/rVID implementation Marc Zyngier
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

Although it is safe for now, do condition the returning of
a msis_require_devid capability on the irqchip being a GICv3.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/arm.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index d625904633c0..0d4c8de27d1e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -195,7 +195,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		if (!kvm)
 			r = -EINVAL;
 		else
-			r = kvm->arch.vgic.msis_require_devid;
+			r = (irqchip_is_gic_v3(kvm) &&
+			     kvm->arch.vgic.msis_require_devid);
 		break;
 	case KVM_CAP_ARM_USER_IRQ:
 		/*
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (20 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 21/23] KVM: arm64: Tighten msis_require_devid reporting Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  2020-09-04 16:00   ` Jonathan Cameron
  2020-09-29 15:13   ` Lorenzo Pieralisi
  2020-09-03 15:26 ` [PATCH 23/23] KVM: arm64: Add debugfs files for the rVIC/rVID implementation Marc Zyngier
  22 siblings, 2 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

The rVIC (reduced Virtual Interrupt Controller), and its rVID
(reduced Virtual Interrupt Distributor) companion are the two
parts of a PV interrupt controller architecture, aiming at supporting
VMs with minimal interrupt requirements.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_host.h |    7 +-
 arch/arm64/include/asm/kvm_irq.h  |    2 +
 arch/arm64/include/uapi/asm/kvm.h |    9 +
 arch/arm64/kvm/Makefile           |    2 +-
 arch/arm64/kvm/arm.c              |    3 +
 arch/arm64/kvm/hypercalls.c       |    7 +
 arch/arm64/kvm/rvic-cpu.c         | 1073 +++++++++++++++++++++++++++++
 include/kvm/arm_rvic.h            |   41 ++
 include/linux/irqchip/irq-rvic.h  |    4 +
 include/uapi/linux/kvm.h          |    2 +
 10 files changed, 1148 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm64/kvm/rvic-cpu.c
 create mode 100644 include/kvm/arm_rvic.h

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 5dd92873d40f..381d3ff6e0b7 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -35,6 +35,7 @@
 #include <kvm/arm_vgic.h>
 #include <kvm/arm_arch_timer.h>
 #include <kvm/arm_pmu.h>
+#include <kvm/arm_rvic.h>
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
@@ -102,6 +103,7 @@ struct kvm_arch {
 	enum kvm_irqchip_type	irqchip_type;
 	bool			irqchip_finalized;
 	struct kvm_irqchip_flow	irqchip_flow;
+	void			*irqchip_data;
 	struct vgic_dist	vgic;
 
 	/* Mandated version of PSCI */
@@ -324,7 +326,10 @@ struct kvm_vcpu_arch {
 	} host_debug_state;
 
 	/* VGIC state */
-	struct vgic_cpu vgic_cpu;
+	union {
+		struct vgic_cpu vgic_cpu;
+		struct rvic rvic;
+	};
 	struct arch_timer_cpu timer_cpu;
 	struct kvm_pmu pmu;
 
diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
index 05fbe5241642..bb1666093f80 100644
--- a/arch/arm64/include/asm/kvm_irq.h
+++ b/arch/arm64/include/asm/kvm_irq.h
@@ -11,11 +11,13 @@ enum kvm_irqchip_type {
 	IRQCHIP_USER,		/* Implemented in userspace */
 	IRQCHIP_GICv2,		/* v2 on v2, or v2 on v3 */
 	IRQCHIP_GICv3,		/* v3 on v3 */
+	IRQCHIP_RVIC,		/* PV irqchip */
 };
 
 #define irqchip_in_kernel(k)	((k)->arch.irqchip_type != IRQCHIP_USER)
 #define irqchip_is_gic_v2(k)	((k)->arch.irqchip_type == IRQCHIP_GICv2)
 #define irqchip_is_gic_v3(k)	((k)->arch.irqchip_type == IRQCHIP_GICv3)
+#define irqchip_is_rvic(k)	((k)->arch.irqchip_type == IRQCHIP_RVIC)
 
 #define irqchip_finalized(k)	((k)->arch.irqchip_finalized)
 
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index ba85bb23f060..9fc26c84903f 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -335,6 +335,15 @@ struct kvm_vcpu_events {
 #define KVM_ARM_VCPU_PVTIME_CTRL	2
 #define   KVM_ARM_VCPU_PVTIME_IPA	0
 
+/*
+ * Device Control API: ARM RVIC. We only use the group, not the group
+ * attributes. They must be set to 0 for now.
+ */
+#define KVM_DEV_ARM_RVIC_GRP_NR_IRQS	0
+#define   KVM_DEV_ARM_RVIC_GRP_NR_TRUSTED_MASK	0xffff
+#define   KVM_DEV_ARM_RVIC_GRP_NR_TOTAL_MASK	(0xffff << 16)
+#define KVM_DEV_ARM_RVIC_GRP_INIT	1
+
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_VCPU2_SHIFT		28
 #define KVM_ARM_IRQ_VCPU2_MASK		0xf
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 99977c1972cc..e378293ce99b 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -16,7 +16,7 @@ kvm-y := $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o \
 	 inject_fault.o regmap.o va_layout.o hyp.o handle_exit.o \
 	 guest.o debug.o reset.o sys_regs.o \
 	 vgic-sys-reg-v3.o fpsimd.o pmu.o \
-	 aarch32.o arch_timer.o \
+	 aarch32.o arch_timer.o rvic-cpu.o \
 	 vgic/vgic.o vgic/vgic-init.o \
 	 vgic/vgic-irqfd.o vgic/vgic-v2.o \
 	 vgic/vgic-v3.o vgic/vgic-v4.o \
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 0d4c8de27d1e..bf0b11bdce84 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -41,6 +41,7 @@
 #include <kvm/arm_hypercalls.h>
 #include <kvm/arm_pmu.h>
 #include <kvm/arm_psci.h>
+#include <kvm/arm_rvic.h>
 
 #ifdef REQUIRES_VIRT
 __asm__(".arch_extension	virt");
@@ -1402,6 +1403,8 @@ static int init_subsystems(void)
 	switch (err) {
 	case 0:
 		vgic_present = true;
+		if (kvm_register_rvic_device())
+			kvm_err("Failed to register rvic device type\n");
 		break;
 	case -ENODEV:
 	case -ENXIO:
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 550dfa3e53cd..f6620be74ce5 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -8,6 +8,9 @@
 
 #include <kvm/arm_hypercalls.h>
 #include <kvm/arm_psci.h>
+#include <kvm/arm_rvic.h>
+
+#include <linux/irqchip/irq-rvic.h>
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
@@ -62,6 +65,10 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 		if (gpa != GPA_INVALID)
 			val = gpa;
 		break;
+	case SMC64_RVIC_BASE ... SMC64_RVIC_LAST:
+		return kvm_rvic_handle_hcall(vcpu);
+	case SMC64_RVID_BASE ... SMC64_RVID_LAST:
+		return kvm_rvid_handle_hcall(vcpu);
 	default:
 		return kvm_psci_call(vcpu);
 	}
diff --git a/arch/arm64/kvm/rvic-cpu.c b/arch/arm64/kvm/rvic-cpu.c
new file mode 100644
index 000000000000..5fb200c637d9
--- /dev/null
+++ b/arch/arm64/kvm/rvic-cpu.c
@@ -0,0 +1,1073 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * rVIC/rVID PV interrupt controller implementation for KVM/arm64.
+ *
+ * Copyright 2020 Google LLC.
+ * Author: Marc Zyngier <maz@kernel.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/kvm_host.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include <kvm/arm_hypercalls.h>
+#include <kvm/arm_rvic.h>
+
+#include <linux/irqchip/irq-rvic.h>
+
+/* FIXME: lock/unlock_all_vcpus */
+#include "vgic/vgic.h"
+
+#define kvm_vcpu_to_rvic(v)	(&(v)->arch.rvic)
+#define kvm_rvic_to_vcpu(r)	(container_of((r), struct kvm_vcpu, arch.rvic))
+
+#define rvic_nr_untrusted(r)	((r)->nr_total - (r)->nr_trusted)
+
+struct rvic_vm_data {
+	u16		nr_trusted;
+	u16		nr_total;
+	spinlock_t	lock;
+	/* Map is a dynamically allocated array of (total-trusted) elements */
+	struct {
+		u16	target_vcpu;
+		u16	intid;
+	} rvid_map[];
+};
+
+/*
+ * rvic_irq state machine:
+ *
+ * idle <- S/C -> pending
+ *  ^          /    ^
+ *  |         /     |
+ * U/M       A     U/M
+ *  |       /       |
+ *  v     v         V
+ * masked <- S/C -> masked+pending
+ *
+ * [S]: Set Pending, [C]: Clear Pending
+ * [U]: Unmask, [M]: Mask
+ * [A]: Ack
+ */
+
+static struct rvic_irq *rvic_get_irq(struct rvic *rvic, unsigned int intid)
+{
+	if (intid >= rvic->nr_total)
+		return NULL;
+	return &rvic->irqs[intid];
+}
+
+static bool rvic_irq_queued(struct rvic_irq *irq)
+{
+	return !list_empty(&irq->delivery_entry);
+}
+
+/* RVIC primitives. They all imply that the RVIC lock is held */
+static void __rvic_enable(struct rvic *rvic)
+{
+	rvic->enabled = true;
+}
+
+static void __rvic_disable(struct rvic *rvic)
+{
+	rvic->enabled = false;
+}
+
+static bool __rvic_is_enabled(struct rvic *rvic)
+{
+	return rvic->enabled;
+}
+
+static void __rvic_set_pending(struct rvic *rvic, unsigned int intid)
+{
+	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
+	unsigned long flags;
+
+	if (!__rvic_is_enabled(rvic)) {
+		pr_debug("dropping intid %u\n", intid);
+		return;
+	}
+
+	spin_lock_irqsave(&irq->lock, flags);
+
+	irq->pending = true;
+	if (!irq->masked && !rvic_irq_queued(irq))
+		list_add_tail(&irq->delivery_entry, &rvic->delivery);
+
+	spin_unlock_irqrestore(&irq->lock, flags);
+}
+
+static void __rvic_clear_pending(struct rvic *rvic, unsigned int intid)
+{
+	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq->lock, flags);
+
+	irq->pending = false;
+	list_del_init(&irq->delivery_entry);
+
+	spin_unlock_irqrestore(&irq->lock, flags);
+}
+
+static bool __rvic_is_pending(struct rvic *rvic, unsigned int intid)
+{
+	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
+	unsigned long flags;
+	bool pend;
+
+	spin_lock_irqsave(&irq->lock, flags);
+	pend = irq->pending;
+	spin_unlock_irqrestore(&irq->lock, flags);
+
+	return pend;
+}
+
+static void __rvic_set_masked(struct rvic *rvic, unsigned int intid)
+{
+	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq->lock, flags);
+
+	irq->masked = true;
+	if (irq->pending)
+		list_del_init(&irq->delivery_entry);
+
+	spin_unlock_irqrestore(&irq->lock, flags);
+}
+
+static void __rvic_clear_masked(struct rvic *rvic, unsigned int intid)
+{
+	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq->lock, flags);
+
+	irq->masked = false;
+	if (__rvic_is_enabled(rvic) && irq->pending && !rvic_irq_queued(irq))
+		list_add_tail(&irq->delivery_entry, &rvic->delivery);
+
+	spin_unlock_irqrestore(&irq->lock, flags);
+}
+
+static unsigned int __rvic_ack(struct rvic *rvic)
+{
+	unsigned int intid = ~0U;
+	struct rvic_irq *irq;
+
+	if (!__rvic_is_enabled(rvic))
+		return intid;
+
+	irq = list_first_entry_or_null(&rvic->delivery, struct rvic_irq,
+				       delivery_entry);
+	if (irq) {
+		intid = irq->intid;
+		__rvic_set_masked(rvic, intid);
+		__rvic_clear_pending(rvic, intid);
+	}
+
+	return intid;
+}
+
+static bool __rvic_can_signal(struct rvic *rvic)
+{
+	return __rvic_is_enabled(rvic) && !list_empty(&rvic->delivery);
+}
+
+static void __rvic_resample(struct rvic *rvic, unsigned int intid)
+{
+	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
+	unsigned long flags;
+	bool pending;
+
+	spin_lock_irqsave(&irq->lock, flags);
+	if (irq->get_line_level) {
+		pending = irq->get_line_level(irq->intid);
+
+		/*
+		 * As part of the resampling, tickle the GIC so that
+		 * new interrupts can trickle in.
+		 */
+		if (!pending && irq->host_irq)
+			irq_set_irqchip_state(irq->host_irq,
+					      IRQCHIP_STATE_ACTIVE, false);
+	} else {
+		pending = irq->line_level;
+	}
+
+	spin_unlock_irqrestore(&irq->lock, flags);
+
+	if (pending)
+		__rvic_set_pending(rvic, intid);
+}
+
+/*
+ * rVIC hypercall handling. All functions assume they are being called
+ * from the vcpu thread that triggers the hypercall.
+ */
+static void __rvic_kick_vcpu(struct kvm_vcpu *vcpu)
+{
+	kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
+	kvm_vcpu_kick(vcpu);
+}
+
+static void __rvic_sync_hcr(struct kvm_vcpu *vcpu, struct rvic *rvic,
+			    bool was_signaling)
+{
+	struct kvm_vcpu *target = kvm_rvic_to_vcpu(rvic);
+	bool signal = __rvic_can_signal(rvic);
+
+	/* We're hitting our own rVIC: update HCR_VI locally */
+	if (vcpu == target) {
+		if (signal)
+			*vcpu_hcr(vcpu) |= HCR_VI;
+		else
+			*vcpu_hcr(vcpu) &= ~HCR_VI;
+
+		return;
+	}
+
+	/*
+	 * Remote rVIC case:
+	 *
+	 * We kick even if the interrupt disappears, as ISR_EL1.I must
+	 * always reflect the state of the rVIC. This forces a reload
+	 * of the vcpu state, making it consistent.
+	 *
+	 * This avoids modifying the target's own copy of HCR_EL2, as
+	 * we are in a cross-vcpu call, and changing it from under its
+	 * feet is dodgy.
+	 */
+	if (was_signaling != signal)
+		__rvic_kick_vcpu(target);
+}
+
+static void rvic_version(struct kvm_vcpu *vcpu)
+{
+	/* ALP0.3 is the name of the game */
+	smccc_set_retval(vcpu, RVIC_STATUS_SUCCESS, RVIC_VERSION(0, 3), 0, 0);
+}
+
+static void rvic_info(struct kvm_vcpu *vcpu)
+{
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	unsigned long what = smccc_get_arg1(vcpu);
+	unsigned long a0, a1;
+
+	switch (what) {
+	case RVIC_INFO_KEY_NR_TRUSTED_INTERRUPTS:
+		a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
+		a1 = rvic->nr_trusted;
+		break;
+	case RVIC_INFO_KEY_NR_UNTRUSTED_INTERRUPTS:
+		a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
+		a1 = rvic_nr_untrusted(rvic);
+		break;
+	default:
+		a0 = RVIx_STATUS_PACK(RVIC_STATUS_ERROR_PARAMETER, 0);
+		a1 = 0;
+		break;
+	}
+
+	smccc_set_retval(vcpu, a0, a1, 0, 0);
+}
+
+static void rvic_enable(struct kvm_vcpu *vcpu)
+{
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	unsigned long flags;
+	bool was_signaling;
+
+	spin_lock_irqsave(&rvic->lock, flags);
+
+	was_signaling = __rvic_can_signal(rvic);
+	__rvic_enable(rvic);
+	__rvic_sync_hcr(vcpu, rvic, was_signaling);
+
+	spin_unlock_irqrestore(&rvic->lock, flags);
+
+	smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0),
+			 0, 0, 0);
+}
+
+static void rvic_disable(struct kvm_vcpu *vcpu)
+{
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	unsigned long flags;
+	bool was_signaling;
+
+	spin_lock_irqsave(&rvic->lock, flags);
+
+	was_signaling = __rvic_can_signal(rvic);
+	__rvic_disable(rvic);
+	__rvic_sync_hcr(vcpu, rvic, was_signaling);
+
+	spin_unlock_irqrestore(&rvic->lock, flags);
+
+	smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0),
+			 0, 0, 0);
+}
+
+typedef void (*rvic_action_fn_t)(struct rvic *, unsigned int);
+
+static int validate_rvic_call(struct kvm_vcpu *vcpu, struct rvic **rvicp,
+			      unsigned int *intidp)
+{
+	unsigned long mpidr = smccc_get_arg1(vcpu);
+	unsigned int intid = smccc_get_arg2(vcpu);
+	struct kvm_vcpu *target;
+	struct rvic *rvic;
+
+	/* FIXME: The spec distinguishes between invalid MPIDR and invalid CPU */
+
+	target = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
+	if (!target) {
+		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_INVALID_CPU, 0),
+				 0, 0, 0);
+		return -1;
+	}
+
+	rvic = kvm_vcpu_to_rvic(target);
+	if (intid >= rvic->nr_total) {
+		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_ERROR_PARAMETER, 1),
+				 0, 0, 0);
+		return -1;
+	}
+
+	*rvicp = rvic;
+	*intidp = intid;
+
+	return 0;
+}
+
+static void __rvic_action(struct kvm_vcpu *vcpu, rvic_action_fn_t action,
+			  bool check_enabled)
+{
+	struct rvic *rvic;
+	unsigned long a0;
+	unsigned long flags;
+	int intid;
+
+	if (validate_rvic_call(vcpu, &rvic, &intid))
+		return;
+
+	spin_lock_irqsave(&rvic->lock, flags);
+
+	if (unlikely(check_enabled && !__rvic_is_enabled(rvic))) {
+		a0 = RVIx_STATUS_PACK(RVIC_STATUS_DISABLED, 0);
+	} else {
+		bool was_signaling = __rvic_can_signal(rvic);
+		action(rvic, intid);
+		__rvic_sync_hcr(vcpu, rvic, was_signaling);
+		a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
+	}
+
+	spin_unlock_irqrestore(&rvic->lock, flags);
+
+	smccc_set_retval(vcpu, a0, 0, 0, 0);
+}
+
+static void rvic_set_masked(struct kvm_vcpu *vcpu)
+{
+	__rvic_action(vcpu, __rvic_set_masked, false);
+}
+
+static void rvic_clear_masked(struct kvm_vcpu *vcpu)
+{
+	__rvic_action(vcpu, __rvic_clear_masked, false);
+}
+
+static void rvic_clear_pending(struct kvm_vcpu *vcpu)
+{
+	__rvic_action(vcpu, __rvic_clear_pending, false);
+}
+
+static void rvic_signal(struct kvm_vcpu *vcpu)
+{
+	__rvic_action(vcpu, __rvic_set_pending, true);
+}
+
+static void rvic_is_pending(struct kvm_vcpu *vcpu)
+{
+	unsigned long flags;
+	struct rvic *rvic;
+	int intid;
+	bool res;
+
+	if (validate_rvic_call(vcpu, &rvic, &intid))
+		return;
+
+	spin_lock_irqsave(&rvic->lock, flags);
+
+	res = __rvic_is_pending(rvic, intid);
+
+	spin_unlock_irqrestore(&rvic->lock, flags);
+
+	smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0),
+			 res, 0, 0);
+}
+
+/*
+ * Ack and Resample are the only "interesting" operations that are
+ * strictly per-CPU.
+ */
+static void rvic_acknowledge(struct kvm_vcpu *vcpu)
+{
+	unsigned long a0, a1;
+	unsigned long flags;
+	unsigned int intid;
+	struct rvic *rvic;
+
+	rvic = kvm_vcpu_to_rvic(vcpu);
+
+	spin_lock_irqsave(&rvic->lock, flags);
+
+	if (unlikely(!__rvic_is_enabled(rvic))) {
+		a0 = RVIx_STATUS_PACK(RVIC_STATUS_DISABLED, 0);
+		a1 = 0;
+	} else {
+		intid = __rvic_ack(rvic);
+		__rvic_sync_hcr(vcpu, rvic, true);
+		if (unlikely(intid >= rvic->nr_total)) {
+			a0 = RVIx_STATUS_PACK(RVIC_STATUS_NO_INTERRUPTS, 0);
+			a1 = 0;
+		} else {
+			a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
+			a1 = intid;
+		}
+	}
+
+	spin_unlock_irqrestore(&rvic->lock, flags);
+
+	smccc_set_retval(vcpu, a0, a1, 0, 0);
+}
+
+static void rvic_resample(struct kvm_vcpu *vcpu)
+{
+	unsigned int intid = smccc_get_arg1(vcpu);
+	unsigned long flags;
+	unsigned long a0;
+	struct rvic *rvic;
+
+	rvic = kvm_vcpu_to_rvic(vcpu);
+
+	spin_lock_irqsave(&rvic->lock, flags);
+
+	if (unlikely(intid >= rvic->nr_trusted)) {
+		a0 = RVIx_STATUS_PACK(RVIC_STATUS_ERROR_PARAMETER, 0);
+	} else {
+		__rvic_resample(rvic, intid);
+
+		/*
+		 * Don't bother finding out if we were signalling, we
+		 * will update HCR_EL2 anyway as we are guaranteed not
+		 * to be in a cross-call.
+		 */
+		__rvic_sync_hcr(vcpu, rvic, true);
+		a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
+	}
+
+	spin_unlock_irqrestore(&rvic->lock, flags);
+
+	smccc_set_retval(vcpu, a0, 0, 0, 0);
+}
+
+int kvm_rvic_handle_hcall(struct kvm_vcpu *vcpu)
+{
+	pr_debug("RVIC: HC %08x", (unsigned int)smccc_get_function(vcpu));
+	switch (smccc_get_function(vcpu)) {
+	case SMC64_RVIC_VERSION:
+		rvic_version(vcpu);
+		break;
+	case SMC64_RVIC_INFO:
+		rvic_info(vcpu);
+		break;
+	case SMC64_RVIC_ENABLE:
+		rvic_enable(vcpu);
+		break;
+	case SMC64_RVIC_DISABLE:
+		rvic_disable(vcpu);
+		break;
+	case SMC64_RVIC_SET_MASKED:
+		rvic_set_masked(vcpu);
+		break;
+	case SMC64_RVIC_CLEAR_MASKED:
+		rvic_clear_masked(vcpu);
+		break;
+	case SMC64_RVIC_IS_PENDING:
+		rvic_is_pending(vcpu);
+		break;
+	case SMC64_RVIC_SIGNAL:
+		rvic_signal(vcpu);
+		break;
+	case SMC64_RVIC_CLEAR_PENDING:
+		rvic_clear_pending(vcpu);
+		break;
+	case SMC64_RVIC_ACKNOWLEDGE:
+		rvic_acknowledge(vcpu);
+		break;
+	case SMC64_RVIC_RESAMPLE:
+		rvic_resample(vcpu);
+		break;
+	default:
+		smccc_set_retval(vcpu, SMCCC_RET_NOT_SUPPORTED, 0, 0, 0);
+		break;
+	}
+
+	return 1;
+}
+
+static void rvid_version(struct kvm_vcpu *vcpu)
+{
+	/* ALP0.3 is the name of the game */
+	smccc_set_retval(vcpu, RVID_STATUS_SUCCESS, RVID_VERSION(0, 3), 0, 0);
+}
+
+static void rvid_map(struct kvm_vcpu *vcpu)
+{
+	unsigned long input = smccc_get_arg1(vcpu);
+	unsigned long mpidr = smccc_get_arg2(vcpu);
+	unsigned int intid = smccc_get_arg3(vcpu);
+	unsigned long flags;
+	struct rvic_vm_data *data;
+	struct kvm_vcpu *target;
+
+	data = vcpu->kvm->arch.irqchip_data;
+
+	if (input > rvic_nr_untrusted(data)) {
+		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVID_STATUS_ERROR_PARAMETER, 0),
+				 0, 0, 0);
+		return;
+	}
+
+	/* FIXME: different error from RVIC. Why? */
+	target = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
+	if (!target) {
+		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVID_STATUS_ERROR_PARAMETER, 1),
+				 0, 0, 0);
+		return;
+	}
+
+	if (intid < data->nr_trusted || intid >= data->nr_total) {
+		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVID_STATUS_ERROR_PARAMETER, 2),
+				 0, 0, 0);
+		return;
+	}
+
+	spin_lock_irqsave(&data->lock, flags);
+	data->rvid_map[input].target_vcpu	= target->vcpu_id;
+	data->rvid_map[input].intid		= intid;
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	smccc_set_retval(vcpu, 0, 0, 0, 0);
+}
+
+static void rvid_unmap(struct kvm_vcpu *vcpu)
+{
+	unsigned long input = smccc_get_arg1(vcpu);
+	unsigned long flags;
+	struct rvic_vm_data *data;
+
+	data = vcpu->kvm->arch.irqchip_data;
+
+	if (input > rvic_nr_untrusted(data)) {
+		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVID_STATUS_ERROR_PARAMETER, 0),
+				 0, 0, 0);
+		return;
+	}
+
+	spin_lock_irqsave(&data->lock, flags);
+	data->rvid_map[input].target_vcpu	= 0;
+	data->rvid_map[input].intid		= 0;
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	smccc_set_retval(vcpu, 0, 0, 0, 0);
+}
+
+int kvm_rvid_handle_hcall(struct kvm_vcpu *vcpu)
+{
+	pr_debug("RVID: HC %08x", (unsigned int)smccc_get_function(vcpu));
+	switch (smccc_get_function(vcpu)) {
+	case SMC64_RVID_VERSION:
+		rvid_version(vcpu);
+		break;
+	case SMC64_RVID_MAP:
+		rvid_map(vcpu);
+		break;
+	case SMC64_RVID_UNMAP:
+		rvid_unmap(vcpu);
+		break;
+	default:
+		smccc_set_retval(vcpu, SMCCC_RET_NOT_SUPPORTED, 0, 0, 0);
+		break;
+	}
+
+	return 1;
+}
+
+/*
+ * KVM internal interface to the rVIC
+ */
+
+/* This *must* be called from the vcpu thread */
+static void rvic_flush_signaling_state(struct kvm_vcpu *vcpu)
+{
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	unsigned long flags;
+
+	spin_lock_irqsave(&rvic->lock, flags);
+
+	__rvic_sync_hcr(vcpu, rvic, true);
+
+	spin_unlock_irqrestore(&rvic->lock, flags);
+}
+
+/* This can be called from any context */
+static void rvic_vcpu_inject_irq(struct kvm_vcpu *vcpu, unsigned int intid,
+				 bool level)
+{
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	unsigned long flags;
+	bool prev;
+
+	spin_lock_irqsave(&rvic->lock, flags);
+
+	if (WARN_ON(intid >= rvic->nr_total))
+		goto out;
+
+	/*
+	 * Although really ugly, this should be safe as we hold the
+	 * rvic lock, and the only path that uses this information is
+	 * resample, which takes this lock too.
+	 */
+	if (!rvic->irqs[intid].get_line_level)
+		rvic->irqs[intid].line_level = level;
+
+	if (level) {
+		prev = __rvic_can_signal(rvic);
+		__rvic_set_pending(rvic, intid);
+		if (prev != __rvic_can_signal(rvic))
+			__rvic_kick_vcpu(vcpu);
+	}
+out:
+	spin_unlock_irqrestore(&rvic->lock, flags);
+}
+
+static int rvic_inject_irq(struct kvm *kvm, unsigned int cpu,
+			   unsigned int intid, bool level, void *owner)
+{
+	struct kvm_vcpu *vcpu = kvm_get_vcpu(kvm, cpu);
+	struct rvic *rvic;
+
+	if (unlikely(!vcpu))
+		return -EINVAL;
+
+	rvic = kvm_vcpu_to_rvic(vcpu);
+	if (unlikely(intid >= rvic->nr_total))
+		return -EINVAL;
+
+	/* Ignore interrupt owner for now */
+	rvic_vcpu_inject_irq(vcpu, intid, level);
+	return 0;
+}
+
+static int rvic_inject_userspace_irq(struct kvm *kvm, unsigned int type,
+				     unsigned int cpu,
+				     unsigned int intid, bool level)
+{
+	struct rvic_vm_data *data = kvm->arch.irqchip_data;
+	unsigned long flags;
+	u16 output;
+
+	switch (type) {
+	case KVM_ARM_IRQ_TYPE_SPI:
+		/*
+		 * Userspace can only inject interrupts that are
+		 * translated by the rvid, so the cpu parameter is
+		 * irrelevant and we override it when resolving the
+		 * translation.
+		 */
+		if (intid >= rvic_nr_untrusted(data))
+			return -EINVAL;
+
+		spin_lock_irqsave(&data->lock, flags);
+		output = data->rvid_map[intid].intid;
+		cpu = data->rvid_map[intid].target_vcpu;
+		spin_unlock_irqrestore(&data->lock, flags);
+
+		/* Silently ignore unmapped interrupts */
+		if (output < data->nr_trusted)
+			return 0;
+
+		return rvic_inject_irq(kvm, cpu, output, level, NULL);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int rvic_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	struct rvic_vm_data *data = vcpu->kvm->arch.irqchip_data;
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	int i;
+
+	/* irqchip not ready yet, we will come back later */
+	if (!data)
+		return 0;
+
+	if (WARN_ON(rvic->irqs))
+		return -EINVAL;
+
+	spin_lock_init(&rvic->lock);
+	INIT_LIST_HEAD(&rvic->delivery);
+	rvic->nr_trusted	= data->nr_trusted;
+	rvic->nr_total		= data->nr_total;
+	rvic->enabled		= false;
+
+	rvic->irqs = kcalloc(rvic->nr_total, sizeof(*rvic->irqs), GFP_ATOMIC);
+	if (!rvic->irqs)
+		return -ENOMEM;
+
+	for (i = 0; i < rvic->nr_total; i++) {
+		struct rvic_irq *irq = &rvic->irqs[i];
+
+		spin_lock_init(&irq->lock);
+		INIT_LIST_HEAD(&irq->delivery_entry);
+		irq->get_line_level	= NULL;
+		irq->intid		= i;
+		irq->host_irq		= 0;
+		irq->pending		= false;
+		irq->masked		= true;
+		irq->line_level		= false;
+	}
+
+	return 0;
+}
+
+static void rvic_destroy(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	int i;
+
+	mutex_lock(&kvm->lock);
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+
+		INIT_LIST_HEAD(&rvic->delivery);
+		kfree(rvic->irqs);
+		rvic->irqs = NULL;
+	}
+
+	mutex_unlock(&kvm->lock);
+}
+
+static int rvic_pending_irq(struct kvm_vcpu *vcpu)
+{
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	unsigned long flags;
+	bool res;
+
+	spin_lock_irqsave(&rvic->lock, flags);
+	res = __rvic_can_signal(rvic);
+	spin_unlock_irqrestore(&rvic->lock, flags);
+
+	return res;
+}
+
+static int rvic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
+			     u32 intid, bool (*get_line_level)(int))
+{
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq->lock, flags);
+	irq->host_irq = host_irq;
+	irq->get_line_level = get_line_level;
+	spin_unlock_irqrestore(&irq->lock, flags);
+
+	return 0;
+}
+
+static int rvic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int intid)
+{
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq->lock, flags);
+	irq->host_irq = 0;
+	irq->get_line_level = NULL;
+	spin_unlock_irqrestore(&irq->lock, flags);
+
+	return 0;
+}
+
+static int rvic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
+			      struct kvm *kvm, int irq_source_id,
+			      int level, bool line_status)
+{
+	/* Abuse the userspace interface to perform the routing*/
+	return rvic_inject_userspace_irq(kvm, KVM_ARM_IRQ_TYPE_SPI, 0,
+					 e->irqchip.pin, level);
+}
+
+static int rvic_set_msi(struct kvm_kernel_irq_routing_entry *e,
+			struct kvm *kvm, int irq_source_id,
+			int level, bool line_status)
+{
+	return -ENODEV;
+}
+
+static int rvic_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
+				 struct kvm *kvm, int irq_source_id,
+				 int level, bool line_status)
+{
+	if (e->type != KVM_IRQ_ROUTING_IRQCHIP)
+		return -EWOULDBLOCK;
+
+	return rvic_irqfd_set_irq(e, kvm, irq_source_id, level, line_status);
+}
+
+static const struct kvm_irqchip_flow rvic_irqchip_flow = {
+	.irqchip_destroy		= rvic_destroy,
+	.irqchip_vcpu_init		= rvic_vcpu_init,
+	/* Nothing to do on block/unblock */
+	/* Nothing to do on load/put */
+	.irqchip_vcpu_pending_irq	= rvic_pending_irq,
+	.irqchip_vcpu_flush_hwstate	= rvic_flush_signaling_state,
+	/* Nothing tp do on sync_hwstate */
+	.irqchip_inject_irq		= rvic_inject_irq,
+	.irqchip_inject_userspace_irq	= rvic_inject_userspace_irq,
+	/* No reset_mapped_irq as we allow spurious interrupts */
+	.irqchip_map_phys_irq		= rvic_map_phys_irq,
+	.irqchip_unmap_phys_irq		= rvic_unmap_phys_irq,
+	.irqchip_irqfd_set_irq		= rvic_irqfd_set_irq,
+	.irqchip_set_msi		= rvic_set_msi,
+	.irqchip_set_irq_inatomic	= rvic_set_irq_inatomic,
+};
+
+static int rvic_setup_default_irq_routing(struct kvm *kvm)
+{
+	struct rvic_vm_data *data = kvm->arch.irqchip_data;
+	unsigned int nr = rvic_nr_untrusted(data);
+	struct kvm_irq_routing_entry *entries;
+	int i, ret;
+
+	entries = kcalloc(nr, sizeof(*entries), GFP_KERNEL);
+	if (!entries)
+		return -ENOMEM;
+
+	for (i = 0; i < nr; i++) {
+		entries[i].gsi = i;
+		entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
+		entries[i].u.irqchip.irqchip = 0;
+		entries[i].u.irqchip.pin = i;
+	}
+	ret = kvm_set_irq_routing(kvm, entries, nr, 0);
+	kfree(entries);
+	return ret;
+}
+
+/* Device management */
+static int rvic_device_create(struct kvm_device *dev, u32 type)
+{
+	struct kvm *kvm = dev->kvm;
+	struct kvm_vcpu *vcpu;
+	int i, ret;
+
+	if (irqchip_in_kernel(kvm))
+		return -EEXIST;
+
+	ret = -EBUSY;
+	if (!lock_all_vcpus(kvm))
+		return ret;
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (vcpu->arch.has_run_once)
+			goto out_unlock;
+	}
+
+	ret = 0;
+
+	/*
+	 * The good thing about not having any HW is that you don't
+	 * get the limitations of the HW...
+	 */
+	kvm->arch.max_vcpus		= KVM_MAX_VCPUS;
+	kvm->arch.irqchip_type		= IRQCHIP_RVIC;
+	kvm->arch.irqchip_flow		= rvic_irqchip_flow;
+	kvm->arch.irqchip_data		= NULL;
+
+out_unlock:
+	unlock_all_vcpus(kvm);
+	return ret;
+}
+
+static void rvic_device_destroy(struct kvm_device *dev)
+{
+	kfree(dev->kvm->arch.irqchip_data);
+	kfree(dev);
+}
+
+static int rvic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+	struct rvic_vm_data *data;
+	struct kvm_vcpu *vcpu;
+	u32 __user *uaddr, val;
+	u16 trusted, total;
+	int i, ret = -ENXIO;
+
+	mutex_lock(&dev->kvm->lock);
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_RVIC_GRP_NR_IRQS:
+		if (attr->attr)
+			break;
+
+		if (dev->kvm->arch.irqchip_data) {
+			ret = -EBUSY;
+			break;
+		}
+
+		uaddr = (u32 __user *)(uintptr_t)attr->addr;
+		if (get_user(val, uaddr)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		trusted = FIELD_GET(KVM_DEV_ARM_RVIC_GRP_NR_TRUSTED_MASK, val);
+		total   = FIELD_GET(KVM_DEV_ARM_RVIC_GRP_NR_TOTAL_MASK, val);
+		if (total < trusted || trusted < 32 || total < 64 ||
+		    trusted % 32 || total % 32 || total > 2048) {
+			ret = -EINVAL;
+			break;
+		}
+
+		data = kzalloc(struct_size(data, rvid_map, (total - trusted)),
+			       GFP_KERNEL);
+		if (!data) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		data->nr_trusted = trusted;
+		data->nr_total = total;
+		spin_lock_init(&data->lock);
+		/* Default to no mapping */
+		for (i = 0; i < (total - trusted); i++) {
+			/*
+			 * an intid < nr_trusted is invalid as the
+			 * result of a translation through the rvid,
+			 * hence the input in unmapped.
+			 */
+			data->rvid_map[i].target_vcpu = 0;
+			data->rvid_map[i].intid = 0;
+		}
+
+		dev->kvm->arch.irqchip_data = data;
+
+		ret = 0;
+		break;
+
+	case KVM_DEV_ARM_RVIC_GRP_INIT:
+		if (attr->attr)
+			break;
+
+		if (!dev->kvm->arch.irqchip_data)
+			break;
+
+		ret = 0;
+
+		/* Init the rvic on any already created vcpu */
+		kvm_for_each_vcpu(i, vcpu, dev->kvm) {
+			ret = rvic_vcpu_init(vcpu);
+			if (ret)
+				break;
+		}
+
+		if (!ret)
+			ret = rvic_setup_default_irq_routing(dev->kvm);
+		if (!ret)
+			dev->kvm->arch.irqchip_finalized = true;
+		break;
+
+	default:
+		break;
+	}
+
+	mutex_unlock(&dev->kvm->lock);
+
+	return ret;
+}
+
+static int rvic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+	struct rvic_vm_data *data;
+	u32 __user *uaddr, val;
+	int ret = -ENXIO;
+
+	mutex_lock(&dev->kvm->lock);
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_RVIC_GRP_NR_IRQS:
+		if (attr->attr)
+			break;
+
+		data = dev->kvm->arch.irqchip_data;
+		if (!data)
+			break;
+
+		val  = FIELD_PREP(KVM_DEV_ARM_RVIC_GRP_NR_TRUSTED_MASK,
+					 data->nr_trusted);
+		val |= FIELD_PREP(KVM_DEV_ARM_RVIC_GRP_NR_TOTAL_MASK,
+					 data->nr_total);
+
+		uaddr = (u32 __user *)(uintptr_t)attr->addr;
+		ret = put_user(val, uaddr);
+		break;
+
+	default:
+		break;
+	}
+
+	mutex_unlock(&dev->kvm->lock);
+
+	return ret;
+}
+
+static int rvic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+	int ret = -ENXIO;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_RVIC_GRP_NR_IRQS:
+	case KVM_DEV_ARM_RVIC_GRP_INIT:
+		if (attr->attr)
+			break;
+		ret = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static const struct kvm_device_ops rvic_dev_ops = {
+	.name		= "kvm-arm-rvic",
+	.create		= rvic_device_create,
+	.destroy	= rvic_device_destroy,
+	.set_attr	= rvic_set_attr,
+	.get_attr	= rvic_get_attr,
+	.has_attr	= rvic_has_attr,
+};
+
+int kvm_register_rvic_device(void)
+{
+	return kvm_register_device_ops(&rvic_dev_ops, KVM_DEV_TYPE_ARM_RVIC);
+}
diff --git a/include/kvm/arm_rvic.h b/include/kvm/arm_rvic.h
new file mode 100644
index 000000000000..9e67a83fa384
--- /dev/null
+++ b/include/kvm/arm_rvic.h
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * rVIC/rVID PV interrupt controller implementation for KVM/arm64.
+ *
+ * Copyright 2020 Google LLC.
+ * Author: Marc Zyngier <maz@kernel.org>
+ */
+
+#ifndef __KVM_ARM_RVIC_H__
+#define __KVM_ARM_RVIC_H__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct kvm_vcpu;
+
+struct rvic_irq {
+	spinlock_t		lock;
+	struct list_head	delivery_entry;
+	bool			(*get_line_level)(int intid);
+	unsigned int		intid;
+	unsigned int		host_irq;
+	bool			pending;
+	bool			masked;
+	bool			line_level; /* If get_line_level == NULL */
+};
+
+struct rvic {
+	spinlock_t		lock;
+	struct list_head	delivery;
+	struct rvic_irq		*irqs;
+	unsigned int		nr_trusted;
+	unsigned int		nr_total;
+	bool			enabled;
+};
+
+int kvm_rvic_handle_hcall(struct kvm_vcpu *vcpu);
+int kvm_rvid_handle_hcall(struct kvm_vcpu *vcpu);
+int kvm_register_rvic_device(void);
+
+#endif
diff --git a/include/linux/irqchip/irq-rvic.h b/include/linux/irqchip/irq-rvic.h
index 4545c1e89741..b188773729fb 100644
--- a/include/linux/irqchip/irq-rvic.h
+++ b/include/linux/irqchip/irq-rvic.h
@@ -57,6 +57,8 @@
 #define SMC64_RVIC_ACKNOWLEDGE		SMC64_RVIC_FN(9)
 #define SMC64_RVIC_RESAMPLE		SMC64_RVIC_FN(10)
 
+#define SMC64_RVIC_LAST			SMC64_RVIC_RESAMPLE
+
 #define RVIC_INFO_KEY_NR_TRUSTED_INTERRUPTS	0
 #define RVIC_INFO_KEY_NR_UNTRUSTED_INTERRUPTS	1
 
@@ -82,6 +84,8 @@
 #define SMC64_RVID_MAP			SMC64_RVID_FN(1)
 #define SMC64_RVID_UNMAP		SMC64_RVID_FN(2)
 
+#define SMC64_RVID_LAST			SMC64_RVID_UNMAP
+
 #define RVID_VERSION(M, m)		RVIx_VERSION((M), (m))
 
 #define RVID_VERSION_MAJOR(v)		RVIx_VERSION_MAJOR((v))
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index f6d86033c4fa..6d245d2dc9e6 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1264,6 +1264,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_XIVE		KVM_DEV_TYPE_XIVE
 	KVM_DEV_TYPE_ARM_PV_TIME,
 #define KVM_DEV_TYPE_ARM_PV_TIME	KVM_DEV_TYPE_ARM_PV_TIME
+	KVM_DEV_TYPE_ARM_RVIC,
+#define KVM_DEV_TYPE_ARM_RVIC		KVM_DEV_TYPE_ARM_RVIC
 	KVM_DEV_TYPE_MAX,
 };
 
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 23/23] KVM: arm64: Add debugfs files for the rVIC/rVID implementation
  2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
                   ` (21 preceding siblings ...)
  2020-09-03 15:26 ` [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation Marc Zyngier
@ 2020-09-03 15:26 ` Marc Zyngier
  22 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-03 15:26 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel; +Cc: Lorenzo Pieralisi, kernel-team

It turns out that having these debugfs information is really
useful when trying to understand what is going wrong in a
guest, or even in the host kernel...

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/rvic-cpu.c | 140 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)

diff --git a/arch/arm64/kvm/rvic-cpu.c b/arch/arm64/kvm/rvic-cpu.c
index 5fb200c637d9..0e91bf6633d5 100644
--- a/arch/arm64/kvm/rvic-cpu.c
+++ b/arch/arm64/kvm/rvic-cpu.c
@@ -6,6 +6,7 @@
  * Author: Marc Zyngier <maz@kernel.org>
  */
 
+#include <linux/debugfs.h>
 #include <linux/kernel.h>
 #include <linux/kvm_host.h>
 #include <linux/list.h>
@@ -707,6 +708,8 @@ static int rvic_inject_userspace_irq(struct kvm *kvm, unsigned int type,
 	}
 }
 
+static void rvic_create_debugfs(struct kvm_vcpu *vcpu);
+
 static int rvic_vcpu_init(struct kvm_vcpu *vcpu)
 {
 	struct rvic_vm_data *data = vcpu->kvm->arch.irqchip_data;
@@ -743,6 +746,8 @@ static int rvic_vcpu_init(struct kvm_vcpu *vcpu)
 		irq->line_level		= false;
 	}
 
+	rvic_create_debugfs(vcpu);
+
 	return 0;
 }
 
@@ -913,6 +918,8 @@ static void rvic_device_destroy(struct kvm_device *dev)
 	kfree(dev);
 }
 
+static void rvid_create_debugfs(struct kvm *kvm);
+
 static int rvic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
 {
 	struct rvic_vm_data *data;
@@ -969,6 +976,7 @@ static int rvic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
 		}
 
 		dev->kvm->arch.irqchip_data = data;
+		rvid_create_debugfs(dev->kvm);
 
 		ret = 0;
 		break;
@@ -1071,3 +1079,135 @@ int kvm_register_rvic_device(void)
 {
 	return kvm_register_device_ops(&rvic_dev_ops, KVM_DEV_TYPE_ARM_RVIC);
 }
+
+static void rvic_irq_debug_show_one(struct seq_file *s, struct rvic_irq *irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq->lock, flags);
+
+	seq_printf(s, "%d: [%d] %c %c %ps %c %c\n",
+		   irq->intid, irq->host_irq,
+		   irq->pending ? 'P' : 'p',
+		   irq->masked ? 'M' : 'm',
+		   irq->get_line_level,
+		   irq->get_line_level ? 'x' : (irq->line_level ? 'H' : 'L'),
+		   rvic_irq_queued(irq) ? 'Q' : 'i');
+
+	spin_unlock_irqrestore(&irq->lock, flags);
+}
+
+static int rvic_irq_debug_show(struct seq_file *s, void *p)
+{
+	rvic_irq_debug_show_one(s, s->private);
+	return 0;
+}
+
+static int rvic_irq_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, rvic_irq_debug_show, inode->i_private);
+}
+
+static const struct file_operations rvic_irq_debug_fops = {
+	.open		= rvic_irq_debug_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int rvic_debug_show(struct seq_file *s, void *p)
+{
+	struct kvm_vcpu *vcpu = s->private;
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	struct rvic_irq *irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rvic->lock, flags);
+
+	seq_printf(s, "%s\n", rvic->enabled ? "Enabled" : "Disabled");
+	seq_printf(s, "%d Trusted\n", rvic->nr_trusted);
+	seq_printf(s, "%d Total\n", rvic->nr_total);
+	list_for_each_entry(irq, &rvic->delivery, delivery_entry)
+		rvic_irq_debug_show_one(s, irq);
+
+	spin_unlock_irqrestore(&rvic->lock, flags);
+
+	return 0;
+}
+
+static int rvic_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, rvic_debug_show, inode->i_private);
+}
+
+static const struct file_operations rvic_debug_fops = {
+	.open		= rvic_debug_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void rvic_create_debugfs(struct kvm_vcpu *vcpu)
+{
+	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
+	struct dentry *rvic_root;
+	char dname[128];
+	int i;
+
+	snprintf(dname, sizeof(dname), "rvic-%d", vcpu->vcpu_id);
+	rvic_root = debugfs_create_dir(dname, vcpu->kvm->debugfs_dentry);
+	if (!rvic_root)
+		return;
+
+	debugfs_create_file("state", 0444, rvic_root, vcpu, &rvic_debug_fops);
+	for (i = 0; i < rvic->nr_total; i++) {
+		snprintf(dname, sizeof(dname), "%d", i);
+		debugfs_create_file(dname, 0444, rvic_root,
+				    rvic_get_irq(rvic, i),
+				    &rvic_irq_debug_fops);
+	}
+}
+
+static int rvid_debug_show(struct seq_file *s, void *p)
+{
+	struct kvm *kvm = s->private;
+	struct rvic_vm_data *data = kvm->arch.irqchip_data;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	seq_printf(s, "%d Trusted\n", data->nr_trusted);
+	seq_printf(s, "%d Total\n", data->nr_total);
+
+	for (i = 0; i < rvic_nr_untrusted(data); i++) {
+		if (data->rvid_map[i].intid < data->nr_trusted)
+			continue;
+
+		seq_printf(s, "%4u: vcpu-%u %u\n",
+			   i, data->rvid_map[i].target_vcpu,
+			   data->rvid_map[i].intid);
+	}
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int rvid_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, rvid_debug_show, inode->i_private);
+}
+
+static const struct file_operations rvid_debug_fops = {
+	.open		= rvid_debug_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void rvid_create_debugfs(struct kvm *kvm)
+{
+	debugfs_create_file("rvid", 0444, kvm->debugfs_dentry,
+			    kvm, &rvid_debug_fops);
+}
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH 02/23] irqchip/rvic: Add support for untrusted interrupt allocation
  2020-09-03 15:25 ` [PATCH 02/23] irqchip/rvic: Add support for untrusted interrupt allocation Marc Zyngier
@ 2020-09-04 13:40   ` Jonathan Cameron
  0 siblings, 0 replies; 35+ messages in thread
From: Jonathan Cameron @ 2020-09-04 13:40 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Lorenzo Pieralisi, kvm, kernel-team, kvmarm, linux-arm-kernel

On Thu,  3 Sep 2020 16:25:49 +0100
Marc Zyngier <maz@kernel.org> wrote:

> Signed-off-by: Marc Zyngier <maz@kernel.org>
Hi Marc,

One trivial comment inline.

> ---
>  drivers/irqchip/irq-rvic.c | 47 +++++++++++++++++++++++++++++++++++---
>  1 file changed, 44 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-rvic.c b/drivers/irqchip/irq-rvic.c
> index 6f37aa4318b6..2747a452202f 100644
> --- a/drivers/irqchip/irq-rvic.c
> +++ b/drivers/irqchip/irq-rvic.c
> @@ -37,6 +37,8 @@ static DEFINE_PER_CPU(unsigned long *, trusted_masked);
>  struct rvic_data {
>  	struct fwnode_handle	*fwnode;
>  	struct irq_domain	*domain;
> +	unsigned long 		*bitmap;
> +	struct mutex		lock;

Nitpick. Good to document the scope of that lock. It's obvious in this
patch but might not be 10 years down the line!

>  	unsigned int		nr_trusted;
>  	unsigned int		nr_untrusted;
>  };
...

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 03/23] irqchip: Add Reduced Virtual Interrupt Distributor support
  2020-09-03 15:25 ` [PATCH 03/23] irqchip: Add Reduced Virtual Interrupt Distributor support Marc Zyngier
@ 2020-09-04 13:56   ` Jonathan Cameron
  0 siblings, 0 replies; 35+ messages in thread
From: Jonathan Cameron @ 2020-09-04 13:56 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Lorenzo Pieralisi, kvm, kernel-team, kvmarm, linux-arm-kernel

On Thu,  3 Sep 2020 16:25:50 +0100
Marc Zyngier <maz@kernel.org> wrote:

> Signed-off-by: Marc Zyngier <maz@kernel.org>

Hi Marc,

Again, only trivial stuff in here from me.

Jonathan

> ---
>  drivers/irqchip/Kconfig          |   6 +
>  drivers/irqchip/Makefile         |   1 +
>  drivers/irqchip/irq-rvid.c       | 259 +++++++++++++++++++++++++++++++
>  include/linux/irqchip/irq-rvic.h |  19 +++
>  4 files changed, 285 insertions(+)
>  create mode 100644 drivers/irqchip/irq-rvid.c
> 
...

> +static int rvid_irq_set_affinity(struct irq_data *data,
> +				 const struct cpumask *mask_val,
> +				 bool force)
> +{
> +	unsigned int old_cpu, cpu;
> +	bool masked, pending;
> +	int err = 0, ret;

Looks like err is set in all paths (might change in later patches of
course!)

> +	u64 mpidr;
> +
> +	if (force)
> +		cpu = cpumask_first(mask_val);
> +	else
> +		cpu = cpumask_any_and(mask_val, cpu_online_mask);
> +
> +	if (cpu >= nr_cpu_ids)
> +		return -EINVAL;
> +
> +	mpidr = cpu_logical_map(cpu) & MPIDR_HWID_BITMASK;
> +	old_cpu = cpumask_first(data->common->effective_affinity);
> +	if (cpu == old_cpu)
> +		return 0;
> +
> +	/* Mask on source */
> +	masked = irqd_irq_masked(data);
> +	if (!masked)
> +		irq_chip_mask_parent(data);
> +
> +	/* Switch to target */
> +	irq_data_update_effective_affinity(data, cpumask_of(cpu));
> +
> +	/* Mask on target */
> +	irq_chip_mask_parent(data);
> +
> +	/* Map the input signal to the new target */
> +	ret = rvid_map(data->hwirq, mpidr, data->parent_data->hwirq);
> +	if (ret != RVID_STATUS_SUCCESS) {
> +		err = -ENXIO;
> +		goto unmask;
> +	}
> +
> +	/* Back to the source */
> +	irq_data_update_effective_affinity(data, cpumask_of(old_cpu));
> +
> +	/* Sample pending state and clear it if necessary */
> +	err = irq_chip_get_parent_state(data, IRQCHIP_STATE_PENDING, &pending);
> +	if (err)
> +		goto unmask;
> +	if (pending)
> +		irq_chip_set_parent_state(data, IRQCHIP_STATE_PENDING, false);
> +
> +	/*
> +	 * To the target again (for good this time), propagating the
> +	 * pending bit if required.
> +	 */
> +	irq_data_update_effective_affinity(data, cpumask_of(cpu));
> +	if (pending)
> +		irq_chip_set_parent_state(data, IRQCHIP_STATE_PENDING, true);
> +unmask:
> +	/* Propagate the masking state */
> +	if (!masked)
> +		irq_chip_unmask_parent(data);
> +
> +	return err;
> +}
> +

...

> +static int rvid_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
> +				 unsigned int nr_irqs, void *arg)
> +{
> +	struct irq_fwspec *fwspec = arg;
> +	unsigned int type = IRQ_TYPE_NONE;
> +	irq_hw_number_t hwirq;
> +	int i, ret;
> +
> +	ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < nr_irqs; i++) {
> +		unsigned int intid = hwirq + i;
> +		unsigned int irq = virq + i;
> +
> +		/* Get the rVIC to allocate any untrusted intid */
> +		ret = irq_domain_alloc_irqs_parent(domain, irq, 1, NULL);
> +		if (WARN_ON(ret))
> +			return ret;
> +
> +		irq_domain_set_hwirq_and_chip(domain, irq, intid,
> +					      &rvid_chip, &rvid);
> +		irqd_set_affinity_on_activate(irq_get_irq_data(irq));
> +	}
> +
> +	return 0;
> +}
> +
> +static void rvid_irq_domain_free(struct irq_domain *domain, unsigned int virq,
> +				 unsigned int nr_irqs)
> +{
> +	int i;
> +
> +	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
> +
> +	for (i = 0; i < nr_irqs; i++) {
> +		struct irq_data *d;

Trivial but for ease of comparison with _alloc, perhaps add

                unsigned int int = virq + i;
> +
> +		d = irq_domain_get_irq_data(domain, virq + i);
> +		irq_set_handler(virq + i, NULL);
> +		irq_domain_reset_irq_data(d);
> +	}
> +}
> +


_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 04/23] irqchip/rvid: Add PCI MSI support
  2020-09-03 15:25 ` [PATCH 04/23] irqchip/rvid: Add PCI MSI support Marc Zyngier
@ 2020-09-04 14:15   ` Jonathan Cameron
  2020-09-05 13:08     ` Marc Zyngier
  0 siblings, 1 reply; 35+ messages in thread
From: Jonathan Cameron @ 2020-09-04 14:15 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Lorenzo Pieralisi, kvm, kernel-team, kvmarm, linux-arm-kernel

On Thu,  3 Sep 2020 16:25:51 +0100
Marc Zyngier <maz@kernel.org> wrote:

> Signed-off-by: Marc Zyngier <maz@kernel.org>
Few minor comments inline.

Thanks,

Jonathan

> ---
>  drivers/irqchip/irq-rvid.c | 182 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 182 insertions(+)
> 
> diff --git a/drivers/irqchip/irq-rvid.c b/drivers/irqchip/irq-rvid.c
> index 953f654e58d4..250f95ad1a09 100644
> --- a/drivers/irqchip/irq-rvid.c
> +++ b/drivers/irqchip/irq-rvid.c
> @@ -12,12 +12,19 @@
>  #include <linux/irq.h>
>  #include <linux/irqchip.h>
>  #include <linux/irqdomain.h>
> +#include <linux/msi.h>
>  
>  #include <linux/irqchip/irq-rvic.h>
>  
>  struct rvid_data {
>  	struct fwnode_handle	*fwnode;
>  	struct irq_domain	*domain;
> +	struct irq_domain	*msi_domain;
> +	struct irq_domain	*pci_domain;
> +	unsigned long		*msi_map;
> +	struct mutex		msi_lock;
> +	u32			msi_base;
> +	u32			msi_nr;
>  };
>  
>  static struct rvid_data rvid;
> @@ -209,6 +216,177 @@ static const struct irq_domain_ops rvid_irq_domain_ops = {
>  	.deactivate	= rvid_irq_domain_deactivate,
>  };
>  
> +#ifdef CONFIG_PCI_MSI
> +/*
> + * The MSI irqchip is completely transparent. The only purpose of the
> + * corresponding irq domain is to provide the MSI allocator, and feed
> + * the allocated inputs to the main rVID irq domain for mapping at the
> + * rVIC level.
> + */
> +static struct irq_chip rvid_msi_chip = {
> +	.name			= "rvid-MSI",
> +	.irq_mask		= irq_chip_mask_parent,
> +	.irq_unmask		= irq_chip_unmask_parent,
> +	.irq_eoi		= irq_chip_eoi_parent,
> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> +	.irq_retrigger		= irq_chip_retrigger_hierarchy,
> +	.irq_set_type		= irq_chip_set_type_parent,
> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> +};
> +
> +static int rvid_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
> +				 unsigned int nr_irqs, void *arg)
> +{
> +	int ret, hwirq, i;
> +
> +	mutex_lock(&rvid.msi_lock);
> +	hwirq = bitmap_find_free_region(rvid.msi_map, rvid.msi_nr,
> +					get_count_order(nr_irqs));
> +	mutex_unlock(&rvid.msi_lock);
> +
> +	if (hwirq < 0)
> +		return -ENOSPC;
> +
> +	for (i = 0; i < nr_irqs; i++) {
> +		/* Use the rVID domain to map the input to something */
> +		struct irq_fwspec fwspec = (struct irq_fwspec) {
> +			.fwnode		= domain->parent->fwnode,
> +			.param_count	= 1,
> +			.param[0]	= rvid.msi_base + hwirq + i,
> +		};
> +
> +		ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &fwspec);
> +		if (WARN_ON(ret))
> +			goto out;
> +
> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> +					      &rvid_msi_chip, &rvid);
> +	}
> +
> +	return 0;
> +
> +out:

I missed this on previous patch, but doesn't the error path need to undo the
irq_domain_alloc_irqs_parent part? irq_domain_free_irqs_parent()


> +	mutex_lock(&rvid.msi_lock);
> +	bitmap_release_region(rvid.msi_map, hwirq, get_count_order(nr_irqs));
> +	mutex_unlock(&rvid.msi_lock);
> +
> +	return ret;
> +}
> +
> +static void rvid_msi_domain_free(struct irq_domain *domain, unsigned int virq,
> +				 unsigned int nr_irqs)
> +{
> +	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
> +	irq_hw_number_t hwirq = d->hwirq;
> +
> +	/* This is a bit cheeky, but hey, recursion never hurt anyone... */
> +	rvid_irq_domain_free(domain, virq, nr_irqs);
> +
> +	mutex_lock(&rvid.msi_lock);
> +	bitmap_release_region(rvid.msi_map, hwirq, get_count_order(nr_irqs));
> +	mutex_unlock(&rvid.msi_lock);
> +}
> +
> +static struct irq_domain_ops rvid_msi_domain_ops = {
> +	.alloc		= rvid_msi_domain_alloc,
> +	.free		= rvid_msi_domain_free,
> +};
> +
> +/*
> + * The PCI irq chip only provides the minimal stuff, as most of the
> + * other methods will be provided as defaults.
> + */
> +static void rvid_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
> +{
> +	/* Random address, the rVID doesn't really have a doorbell */
> +	msg->address_hi = 0;
> +	msg->address_lo = 0xba5e0000;
> +
> +	/*
> +	 * We are called from the PCI domain, and what we program in
> +	 * the device is the rVID input pin, which is located two
> +	 * levels down in the interrupt chain (PCI -> MSI -> rVID).
> +	 */
> +	msg->data = data->parent_data->parent_data->hwirq;
> +}
> +
> +static void rvid_pci_mask(struct irq_data *d)
> +{
> +	pci_msi_mask_irq(d);
> +	irq_chip_mask_parent(d);
> +}
> +
> +static void rvid_pci_unmask(struct irq_data *d)
> +{
> +	pci_msi_unmask_irq(d);
> +	irq_chip_unmask_parent(d);
> +}
> +
> +static struct irq_chip rvid_pci_chip = {
> +	.name			= "PCI-MSI",
> +	.irq_mask		= rvid_pci_mask,
> +	.irq_unmask		= rvid_pci_unmask,
> +	.irq_eoi		= irq_chip_eoi_parent,
> +	.irq_compose_msi_msg	= rvid_compose_msi_msg,
> +	.irq_write_msi_msg	= pci_msi_domain_write_msg,
> +};
> +
> +static struct msi_domain_info rvid_pci_domain_info = {
> +	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
> +		   MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI),
> +	.chip	= &rvid_pci_chip,
> +};
> +
> +static void __init rvid_msi_setup(struct device_node *np)
> +{
> +	if (!of_property_read_bool(np, "msi-controller"))
> +		return;
> +
> +	if (of_property_read_u32_index(np, "msi-range", 0, &rvid.msi_base) ||
> +	    of_property_read_u32_index(np, "msi-range", 1, &rvid.msi_nr)) {

Looks like msi-range isn't defined in any existing bindings, or my grep
fu is broken today.

> +		pr_err("Invalid or missing msi-range\n");
> +		return;
> +	}
> +
> +	mutex_init(&rvid.msi_lock);
> +
> +	rvid.msi_map = bitmap_alloc(rvid.msi_nr, GFP_KERNEL | __GFP_ZERO);

bitmap_zalloc()

> +	if (!rvid.msi_map)
> +		return;
> +
> +	rvid.msi_domain = irq_domain_create_hierarchy(rvid.domain, 0, 0,
> +						      rvid.fwnode,
> +						      &rvid_msi_domain_ops,
> +						      &rvid);
> +	if (!rvid.msi_domain) {
> +		pr_err("Failed to allocate MSI domain\n");
> +		goto out;
> +	}
> +
> +	irq_domain_update_bus_token(rvid.msi_domain, DOMAIN_BUS_NEXUS);
> +
> +	rvid.pci_domain = pci_msi_create_irq_domain(rvid.domain->fwnode,
> +						    &rvid_pci_domain_info,
> +						    rvid.msi_domain);
> +	if (!rvid.pci_domain) {
> +		pr_err("Failed to allocate PCI domain\n");
> +		goto out;
> +	}
> +
> +	pr_info("MSIs available as inputs [%d:%d]\n",
> +		rvid.msi_base, rvid.msi_base + rvid.msi_nr - 1);
> +	return;
> +
> +out:
> +	if (rvid.msi_domain)
> +		irq_domain_remove(rvid.msi_domain);
> +	kfree(rvid.msi_map);
> +}
> +#else
> +static inline void rvid_msi_setup(struct device_node *np) {}
> +#endif
> +
>  static int __init rvid_init(struct device_node *node,
>  			    struct device_node *parent)
>  {
> @@ -253,6 +431,10 @@ static int __init rvid_init(struct device_node *node,
>  		return -ENOMEM;
>  	}
>  
> +	irq_domain_update_bus_token(rvid.domain, DOMAIN_BUS_WIRED);
> +
> +	rvid_msi_setup(node);
> +
>  	return 0;
>  }
>  


_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 05/23] KVM: arm64: Move GIC model out of the distributor
  2020-09-03 15:25 ` [PATCH 05/23] KVM: arm64: Move GIC model out of the distributor Marc Zyngier
@ 2020-09-04 14:37   ` Jonathan Cameron
  0 siblings, 0 replies; 35+ messages in thread
From: Jonathan Cameron @ 2020-09-04 14:37 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Lorenzo Pieralisi, kvm, kernel-team, kvmarm, linux-arm-kernel

On Thu,  3 Sep 2020 16:25:52 +0100
Marc Zyngier <maz@kernel.org> wrote:

> In order to allow more than just GIC implementations in the future,
> let's move the GIC model outside of the distributor. This also
> allows us to back irqchip_in_kernel() with its own irqchip type
> (IRQCHIP_USER), removing another field from the distributor.
> 
> New helpers are provided as a convenience.

Patch looks fine to me. One observation inline.

> 
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
>  arch/arm64/include/asm/kvm_host.h     |  2 ++
>  arch/arm64/include/asm/kvm_irq.h      | 20 ++++++++++++++++++++
>  arch/arm64/kvm/vgic/vgic-debug.c      |  5 +++--
>  arch/arm64/kvm/vgic/vgic-init.c       | 26 ++++++++++++--------------
>  arch/arm64/kvm/vgic/vgic-kvm-device.c | 16 ++++++++++++----
>  arch/arm64/kvm/vgic/vgic-mmio-v3.c    |  2 +-
>  arch/arm64/kvm/vgic/vgic-mmio.c       | 10 ++++------
>  arch/arm64/kvm/vgic/vgic-v3.c         | 20 ++++++++------------
>  include/kvm/arm_vgic.h                |  5 -----
>  9 files changed, 62 insertions(+), 44 deletions(-)
>  create mode 100644 arch/arm64/include/asm/kvm_irq.h
> 

...

> diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
> index 76e2d85789ed..c6fdb1222453 100644
> --- a/arch/arm64/kvm/vgic/vgic-v3.c
> +++ b/arch/arm64/kvm/vgic/vgic-v3.c
> @@ -32,7 +32,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>  	struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3;
> -	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	bool is_v3 = irqchip_is_gic_v3(vcpu->kvm);
>  	int lr;
>  
>  	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
> @@ -48,7 +48,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>  		cpuid = val & GICH_LR_PHYSID_CPUID;
>  		cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>  
> -		if (model == KVM_DEV_TYPE_ARM_VGIC_V3) {
> +		if (is_v3) {
>  			intid = val & ICH_LR_VIRTUAL_ID_MASK;
>  		} else {
>  			intid = val & GICH_LR_VIRTUALID;
> @@ -117,12 +117,11 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>  /* Requires the irq to be locked already */
>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>  {
> -	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	bool is_v2 = irqchip_is_gic_v2(vcpu->kvm);
>  	u64 val = irq->intid;
>  	bool allow_pending = true, is_v2_sgi;
>  
> -	is_v2_sgi = (vgic_irq_is_sgi(irq->intid) &&
> -		     model == KVM_DEV_TYPE_ARM_VGIC_V2);
> +	is_v2_sgi = (vgic_irq_is_sgi(irq->intid) && is_v2);
>  
>  	if (irq->active) {
>  		val |= ICH_LR_ACTIVE_BIT;
> @@ -163,8 +162,7 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>  		if (irq->config == VGIC_CONFIG_EDGE)
>  			irq->pending_latch = false;
>  
> -		if (vgic_irq_is_sgi(irq->intid) &&
> -		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +		if (vgic_irq_is_sgi(irq->intid) && is_v2) {

Clearly its true in the original code, but I'm not sure why we
have a local variable for is_v2_sgi above, but don't use it here.

Looks like it might just be because is_v2_sgi was introduced
as part of a bug fix that didn't go near this block of code?

>  			u32 src = ffs(irq->source);
>  
>  			if (WARN_RATELIMIT(!src, "No SGI source for INTID %d\n",
> @@ -205,10 +203,9 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
>  	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> -	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>  	u32 vmcr;
>  
> -	if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +	if (irqchip_is_gic_v2(vcpu->kvm)) {
>  		vmcr = (vmcrp->ackctl << ICH_VMCR_ACK_CTL_SHIFT) &
>  			ICH_VMCR_ACK_CTL_MASK;
>  		vmcr |= (vmcrp->fiqen << ICH_VMCR_FIQ_EN_SHIFT) &
> @@ -235,12 +232,11 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
>  	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> -	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>  	u32 vmcr;
>  
>  	vmcr = cpu_if->vgic_vmcr;
>  
> -	if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +	if (irqchip_is_gic_v2(vcpu->kvm)) {
>  		vmcrp->ackctl = (vmcr & ICH_VMCR_ACK_CTL_MASK) >>
>  			ICH_VMCR_ACK_CTL_SHIFT;
>  		vmcrp->fiqen = (vmcr & ICH_VMCR_FIQ_EN_MASK) >>
> @@ -285,7 +281,7 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  	 * Also, we don't support any form of IRQ/FIQ bypass.
>  	 * This goes with the spec allowing the value to be RAO/WI.
>  	 */
> -	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
> +	if (irqchip_is_gic_v3(vcpu->kvm)) {
>  		vgic_v3->vgic_sre = (ICC_SRE_EL1_DIB |
>  				     ICC_SRE_EL1_DFB |
>  				     ICC_SRE_EL1_SRE);


_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 12/23] KVM: arm64: Move kvm_vgic_vcpu_pending_irq() to irqchip_flow
  2020-09-03 15:25 ` [PATCH 12/23] KVM: arm64: Move kvm_vgic_vcpu_pending_irq() " Marc Zyngier
@ 2020-09-04 14:57   ` Jonathan Cameron
  0 siblings, 0 replies; 35+ messages in thread
From: Jonathan Cameron @ 2020-09-04 14:57 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Lorenzo Pieralisi, kvm, kernel-team, kvmarm, linux-arm-kernel

On Thu, 3 Sep 2020 16:25:59 +0100
Marc Zyngier <maz@kernel.org> wrote:

> Abstract the calls to kvm_vgic_vcpu_pending_irq() via the irqchip_flow
> structure.
> 
> No functional change.
> 
> Signed-off-by: Marc Zyngier <maz@kernel.org>

A couple of stray lines in here that I think should be in patch 14

Jonathan

> ---
>  arch/arm64/include/asm/kvm_irq.h | 4 ++++
>  arch/arm64/kvm/arm.c             | 4 ++--
>  arch/arm64/kvm/vgic/vgic-init.c  | 1 +
>  arch/arm64/kvm/vgic/vgic.h       | 6 ++++++
>  include/kvm/arm_vgic.h           | 3 ---
>  5 files changed, 13 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_irq.h b/arch/arm64/include/asm/kvm_irq.h
> index 50dfd641cd67..e7a244176ade 100644
> --- a/arch/arm64/include/asm/kvm_irq.h
> +++ b/arch/arm64/include/asm/kvm_irq.h
> @@ -24,6 +24,7 @@ struct kvm_irqchip_flow {
>  	void (*irqchip_vcpu_unblocking)(struct kvm_vcpu *);
>  	void (*irqchip_vcpu_load)(struct kvm_vcpu *);
>  	void (*irqchip_vcpu_put)(struct kvm_vcpu *);
> +	int  (*irqchip_vcpu_pending_irq)(struct kvm_vcpu *);
>  };
>  
>  /*
> @@ -70,4 +71,7 @@ struct kvm_irqchip_flow {
>  #define kvm_irqchip_vcpu_put(v)				\
>  	__vcpu_irqchip_action((v), vcpu_put, (v))
>  
> +#define kvm_irqchip_vcpu_pending_irq(v)			\
> +	__vcpu_irqchip_action_ret((v), vcpu_pending_irq, (v))
> +
>  #endif
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 84d48c312b84..3496d200e488 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -399,8 +399,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
>  int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
>  {
>  	bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF);
> -	return ((irq_lines || kvm_vgic_vcpu_pending_irq(v))
> -		&& !v->arch.power_off && !v->arch.pause);
> +	return ((irq_lines || kvm_irqchip_vcpu_pending_irq(v)) &&
> +		!v->arch.power_off && !v->arch.pause);
>  }
>  
>  bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> index 24b3ed9bae5d..8bb847045ef9 100644
> --- a/arch/arm64/kvm/vgic/vgic-init.c
> +++ b/arch/arm64/kvm/vgic/vgic-init.c
> @@ -22,6 +22,7 @@ static struct kvm_irqchip_flow vgic_irqchip_flow = {
>  	.irqchip_vcpu_unblocking	= kvm_vgic_vcpu_unblocking,
>  	.irqchip_vcpu_load		= kvm_vgic_load,
>  	.irqchip_vcpu_put		= kvm_vgic_put,
> +	.irqchip_vcpu_pending_irq	= kvm_vgic_vcpu_pending_irq,
>  };
>  
>  /*
> diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> index 190737402365..c5511823eec5 100644
> --- a/arch/arm64/kvm/vgic/vgic.h
> +++ b/arch/arm64/kvm/vgic/vgic.h
> @@ -321,7 +321,13 @@ int vgic_v4_init(struct kvm *kvm);
>  void vgic_v4_teardown(struct kvm *kvm);
>  void vgic_v4_configure_vsgis(struct kvm *kvm);
>  
> +int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
> +
>  void kvm_vgic_load(struct kvm_vcpu *vcpu);
>  void kvm_vgic_put(struct kvm_vcpu *vcpu);
>  
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);

Wrong patch?

> +
> +

Nitpick. One line is always enough :)

>  #endif
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index a06d9483e3a6..b2adf9cca334 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -347,14 +347,11 @@ int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
>  int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
>  bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
>  
> -int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
> -
>  #define vgic_initialized(k)	((k)->arch.vgic.initialized)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> -bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>  void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>  void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid);


_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation
  2020-09-03 15:26 ` [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation Marc Zyngier
@ 2020-09-04 16:00   ` Jonathan Cameron
  2020-09-05 13:16     ` Marc Zyngier
  2020-09-29 15:13   ` Lorenzo Pieralisi
  1 sibling, 1 reply; 35+ messages in thread
From: Jonathan Cameron @ 2020-09-04 16:00 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Lorenzo Pieralisi, kvm, kernel-team, kvmarm, linux-arm-kernel

On Thu, 3 Sep 2020 16:26:09 +0100
Marc Zyngier <maz@kernel.org> wrote:

> The rVIC (reduced Virtual Interrupt Controller), and its rVID
> (reduced Virtual Interrupt Distributor) companion are the two
> parts of a PV interrupt controller architecture, aiming at supporting
> VMs with minimal interrupt requirements.
> 
> Signed-off-by: Marc Zyngier <maz@kernel.org>

A few trivial things from a first read through.

> ---
>  arch/arm64/include/asm/kvm_host.h |    7 +-
>  arch/arm64/include/asm/kvm_irq.h  |    2 +
>  arch/arm64/include/uapi/asm/kvm.h |    9 +
>  arch/arm64/kvm/Makefile           |    2 +-
>  arch/arm64/kvm/arm.c              |    3 +
>  arch/arm64/kvm/hypercalls.c       |    7 +
>  arch/arm64/kvm/rvic-cpu.c         | 1073 +++++++++++++++++++++++++++++
>  include/kvm/arm_rvic.h            |   41 ++
>  include/linux/irqchip/irq-rvic.h  |    4 +
>  include/uapi/linux/kvm.h          |    2 +
>  10 files changed, 1148 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm64/kvm/rvic-cpu.c
>  create mode 100644 include/kvm/arm_rvic.h
> 

...

> diff --git a/arch/arm64/kvm/rvic-cpu.c b/arch/arm64/kvm/rvic-cpu.c
> new file mode 100644
> index 000000000000..5fb200c637d9
> --- /dev/null
> +++ b/arch/arm64/kvm/rvic-cpu.c

...

> +
> +static int rvic_inject_irq(struct kvm *kvm, unsigned int cpu,
> +			   unsigned int intid, bool level, void *owner)
> +{
> +	struct kvm_vcpu *vcpu = kvm_get_vcpu(kvm, cpu);
> +	struct rvic *rvic;
> +
> +	if (unlikely(!vcpu))
> +		return -EINVAL;
> +
> +	rvic = kvm_vcpu_to_rvic(vcpu);
> +	if (unlikely(intid >= rvic->nr_total))
> +		return -EINVAL;
> +
> +	/* Ignore interrupt owner for now */
> +	rvic_vcpu_inject_irq(vcpu, intid, level);

For consistency blank line?

> +	return 0;
> +}
> +

...

> +
> +static int rvic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
> +			      struct kvm *kvm, int irq_source_id,
> +			      int level, bool line_status)
> +{
> +	/* Abuse the userspace interface to perform the routing*/

Space before */

> +	return rvic_inject_userspace_irq(kvm, KVM_ARM_IRQ_TYPE_SPI, 0,
> +					 e->irqchip.pin, level);
> +}
> +

...

> +
> +/* Device management */
> +static int rvic_device_create(struct kvm_device *dev, u32 type)
> +{
> +	struct kvm *kvm = dev->kvm;
> +	struct kvm_vcpu *vcpu;
> +	int i, ret;

It's personal preference, but I'd avoid the fiddly
ret handling in the good path. (up to you though!)

ret = 0;
> +
> +	if (irqchip_in_kernel(kvm))
> +		return -EEXIST;
> +
> +	ret = -EBUSY;
> +	if (!lock_all_vcpus(kvm))
> +		return ret;
	if (!lock_all_vcpus(kvm))
		return -EBUSY;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (vcpu->arch.has_run_once) {
			ret = -EBUSY;
> +			goto out_unlock;
		}
> +	}
> +
> +	ret = 0;
> +
> +	/*
> +	 * The good thing about not having any HW is that you don't
> +	 * get the limitations of the HW...
> +	 */
> +	kvm->arch.max_vcpus		= KVM_MAX_VCPUS;
> +	kvm->arch.irqchip_type		= IRQCHIP_RVIC;
> +	kvm->arch.irqchip_flow		= rvic_irqchip_flow;
> +	kvm->arch.irqchip_data		= NULL;
> +
> +out_unlock:
> +	unlock_all_vcpus(kvm);
> +	return ret;
> +}
> +
> +static void rvic_device_destroy(struct kvm_device *dev)
> +{
> +	kfree(dev->kvm->arch.irqchip_data);
> +	kfree(dev);
> +}
> +
> +static int rvic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
> +{
> +	struct rvic_vm_data *data;
> +	struct kvm_vcpu *vcpu;
> +	u32 __user *uaddr, val;
> +	u16 trusted, total;
> +	int i, ret = -ENXIO;
> +
> +	mutex_lock(&dev->kvm->lock);
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_RVIC_GRP_NR_IRQS:
> +		if (attr->attr)
> +			break;
> +
> +		if (dev->kvm->arch.irqchip_data) {
> +			ret = -EBUSY;
> +			break;
> +		}
> +
> +		uaddr = (u32 __user *)(uintptr_t)attr->addr;
> +		if (get_user(val, uaddr)) {
> +			ret = -EFAULT;
> +			break;
> +		}
> +
> +		trusted = FIELD_GET(KVM_DEV_ARM_RVIC_GRP_NR_TRUSTED_MASK, val);
> +		total   = FIELD_GET(KVM_DEV_ARM_RVIC_GRP_NR_TOTAL_MASK, val);
> +		if (total < trusted || trusted < 32 || total < 64 ||
> +		    trusted % 32 || total % 32 || total > 2048) {

As I read the spec, we need at least 32 untrusted. (R0058) 
This condition seems to allow that if trusted = 64 and untrusted = 0


> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		data = kzalloc(struct_size(data, rvid_map, (total - trusted)),
> +			       GFP_KERNEL);
> +		if (!data) {
> +			ret = -ENOMEM;
> +			break;
> +		}
> +
> +		data->nr_trusted = trusted;
> +		data->nr_total = total;
> +		spin_lock_init(&data->lock);
> +		/* Default to no mapping */
> +		for (i = 0; i < (total - trusted); i++) {
> +			/*
> +			 * an intid < nr_trusted is invalid as the
> +			 * result of a translation through the rvid,
> +			 * hence the input in unmapped.
> +			 */
> +			data->rvid_map[i].target_vcpu = 0;
> +			data->rvid_map[i].intid = 0;
> +		}
> +
> +		dev->kvm->arch.irqchip_data = data;
> +
> +		ret = 0;
> +		break;
> +
> +	case KVM_DEV_ARM_RVIC_GRP_INIT:
> +		if (attr->attr)
> +			break;
> +
> +		if (!dev->kvm->arch.irqchip_data)
> +			break;
> +
> +		ret = 0;
> +
> +		/* Init the rvic on any already created vcpu */
> +		kvm_for_each_vcpu(i, vcpu, dev->kvm) {
> +			ret = rvic_vcpu_init(vcpu);
> +			if (ret)
> +				break;
> +		}
> +
> +		if (!ret)
> +			ret = rvic_setup_default_irq_routing(dev->kvm);
> +		if (!ret)
> +			dev->kvm->arch.irqchip_finalized = true;

Personally I'd prefer the more idiomatic 

		if (ret)
			break;

		ret =...
		if (ret)
			break;
		dev->kvm->arch.....

> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	mutex_unlock(&dev->kvm->lock);
> +
> +	return ret;
> +}
> +

...

> +static int rvic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
> +{
> +	int ret = -ENXIO;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_RVIC_GRP_NR_IRQS:
> +	case KVM_DEV_ARM_RVIC_GRP_INIT:
> +		if (attr->attr)
> +			break;
> +		ret = 0;

Trivial:
Early returns?  Bit shorter and easier to read?

> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct kvm_device_ops rvic_dev_ops = {
> +	.name		= "kvm-arm-rvic",
> +	.create		= rvic_device_create,
> +	.destroy	= rvic_device_destroy,
> +	.set_attr	= rvic_set_attr,
> +	.get_attr	= rvic_get_attr,
> +	.has_attr	= rvic_has_attr,
> +};
> +
> +int kvm_register_rvic_device(void)
> +{
> +	return kvm_register_device_ops(&rvic_dev_ops, KVM_DEV_TYPE_ARM_RVIC);
> +}



_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 04/23] irqchip/rvid: Add PCI MSI support
  2020-09-04 14:15   ` Jonathan Cameron
@ 2020-09-05 13:08     ` Marc Zyngier
  0 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-05 13:08 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Lorenzo Pieralisi, kvm, kernel-team, kvmarm, linux-arm-kernel

Hi Jonathan,

On Fri, 04 Sep 2020 15:15:38 +0100,
Jonathan Cameron <Jonathan.Cameron@Huawei.com> wrote:
> 
> On Thu,  3 Sep 2020 16:25:51 +0100
> Marc Zyngier <maz@kernel.org> wrote:
> 
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> Few minor comments inline.
> 
> Thanks,
> 
> Jonathan
> 
> > ---
> >  drivers/irqchip/irq-rvid.c | 182 +++++++++++++++++++++++++++++++++++++
> >  1 file changed, 182 insertions(+)
> > 
> > diff --git a/drivers/irqchip/irq-rvid.c b/drivers/irqchip/irq-rvid.c
> > index 953f654e58d4..250f95ad1a09 100644
> > --- a/drivers/irqchip/irq-rvid.c
> > +++ b/drivers/irqchip/irq-rvid.c
> > @@ -12,12 +12,19 @@
> >  #include <linux/irq.h>
> >  #include <linux/irqchip.h>
> >  #include <linux/irqdomain.h>
> > +#include <linux/msi.h>
> >  
> >  #include <linux/irqchip/irq-rvic.h>
> >  
> >  struct rvid_data {
> >  	struct fwnode_handle	*fwnode;
> >  	struct irq_domain	*domain;
> > +	struct irq_domain	*msi_domain;
> > +	struct irq_domain	*pci_domain;
> > +	unsigned long		*msi_map;
> > +	struct mutex		msi_lock;
> > +	u32			msi_base;
> > +	u32			msi_nr;
> >  };
> >  
> >  static struct rvid_data rvid;
> > @@ -209,6 +216,177 @@ static const struct irq_domain_ops rvid_irq_domain_ops = {
> >  	.deactivate	= rvid_irq_domain_deactivate,
> >  };
> >  
> > +#ifdef CONFIG_PCI_MSI
> > +/*
> > + * The MSI irqchip is completely transparent. The only purpose of the
> > + * corresponding irq domain is to provide the MSI allocator, and feed
> > + * the allocated inputs to the main rVID irq domain for mapping at the
> > + * rVIC level.
> > + */
> > +static struct irq_chip rvid_msi_chip = {
> > +	.name			= "rvid-MSI",
> > +	.irq_mask		= irq_chip_mask_parent,
> > +	.irq_unmask		= irq_chip_unmask_parent,
> > +	.irq_eoi		= irq_chip_eoi_parent,
> > +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> > +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> > +	.irq_retrigger		= irq_chip_retrigger_hierarchy,
> > +	.irq_set_type		= irq_chip_set_type_parent,
> > +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> > +};
> > +
> > +static int rvid_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
> > +				 unsigned int nr_irqs, void *arg)
> > +{
> > +	int ret, hwirq, i;
> > +
> > +	mutex_lock(&rvid.msi_lock);
> > +	hwirq = bitmap_find_free_region(rvid.msi_map, rvid.msi_nr,
> > +					get_count_order(nr_irqs));
> > +	mutex_unlock(&rvid.msi_lock);
> > +
> > +	if (hwirq < 0)
> > +		return -ENOSPC;
> > +
> > +	for (i = 0; i < nr_irqs; i++) {
> > +		/* Use the rVID domain to map the input to something */
> > +		struct irq_fwspec fwspec = (struct irq_fwspec) {
> > +			.fwnode		= domain->parent->fwnode,
> > +			.param_count	= 1,
> > +			.param[0]	= rvid.msi_base + hwirq + i,
> > +		};
> > +
> > +		ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &fwspec);
> > +		if (WARN_ON(ret))
> > +			goto out;
> > +
> > +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> > +					      &rvid_msi_chip, &rvid);
> > +	}
> > +
> > +	return 0;
> > +
> > +out:
> 
> I missed this on previous patch, but doesn't the error path need to undo the
> irq_domain_alloc_irqs_parent part? irq_domain_free_irqs_parent()

Yes, this indeed needs some rework.

[...]

> > +static void __init rvid_msi_setup(struct device_node *np)
> > +{
> > +	if (!of_property_read_bool(np, "msi-controller"))
> > +		return;
> > +
> > +	if (of_property_read_u32_index(np, "msi-range", 0, &rvid.msi_base) ||
> > +	    of_property_read_u32_index(np, "msi-range", 1, &rvid.msi_nr)) {
> 
> Looks like msi-range isn't defined in any existing bindings, or my grep
> fu is broken today.

As hinted at in the cover letter, there is no binding whatsoever for
now, and all the properties are totally made up.

As for the use of "msi-range", most bindings are using some ad-hoc
descriptions of their *outputs* to the downstream irqchip. What I am
describing here is the range of *inputs* into the rVID that can be
used for MSIs.

It we wanted to use an abstraction similar to what exists in the
physical world, then the MSI widget would be a separate component
upstream of the rVID itself. In a way the driver works like that
already (there is a separate MSI domain sitting atop the rVID domain),
and it wouldn't be a big deal to switch to that. We'd need a property
describing the output range of the widget, similar in essence to what
is required for the GICv3 MBI ranges.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation
  2020-09-04 16:00   ` Jonathan Cameron
@ 2020-09-05 13:16     ` Marc Zyngier
  0 siblings, 0 replies; 35+ messages in thread
From: Marc Zyngier @ 2020-09-05 13:16 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Lorenzo Pieralisi, kvm, kernel-team, kvmarm, linux-arm-kernel

On Fri, 04 Sep 2020 17:00:36 +0100,
Jonathan Cameron <Jonathan.Cameron@Huawei.com> wrote:
> 
> On Thu, 3 Sep 2020 16:26:09 +0100
> Marc Zyngier <maz@kernel.org> wrote:

[...]

> > +static int rvic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
> > +{
> > +	struct rvic_vm_data *data;
> > +	struct kvm_vcpu *vcpu;
> > +	u32 __user *uaddr, val;
> > +	u16 trusted, total;
> > +	int i, ret = -ENXIO;
> > +
> > +	mutex_lock(&dev->kvm->lock);
> > +
> > +	switch (attr->group) {
> > +	case KVM_DEV_ARM_RVIC_GRP_NR_IRQS:
> > +		if (attr->attr)
> > +			break;
> > +
> > +		if (dev->kvm->arch.irqchip_data) {
> > +			ret = -EBUSY;
> > +			break;
> > +		}
> > +
> > +		uaddr = (u32 __user *)(uintptr_t)attr->addr;
> > +		if (get_user(val, uaddr)) {
> > +			ret = -EFAULT;
> > +			break;
> > +		}
> > +
> > +		trusted = FIELD_GET(KVM_DEV_ARM_RVIC_GRP_NR_TRUSTED_MASK, val);
> > +		total   = FIELD_GET(KVM_DEV_ARM_RVIC_GRP_NR_TOTAL_MASK, val);
> > +		if (total < trusted || trusted < 32 || total < 64 ||
> > +		    trusted % 32 || total % 32 || total > 2048) {
> 
> As I read the spec, we need at least 32 untrusted. (R0058) 
> This condition seems to allow that if trusted = 64 and untrusted = 0

Well spotted. I think the following would capture the constraints
correctly:

		if (total <= trusted || trusted < 32 || total < 64 ||
		    trusted % 32 || total % 32 || total > 2048) {

On the other hand, I wonder if this code would gain from being
directly written in terms of trusted/untrusted, rather than
trusted/total. It could make the reading against the spec easier.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation
  2020-09-03 15:26 ` [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation Marc Zyngier
  2020-09-04 16:00   ` Jonathan Cameron
@ 2020-09-29 15:13   ` Lorenzo Pieralisi
  2020-09-29 15:27     ` Marc Zyngier
  1 sibling, 1 reply; 35+ messages in thread
From: Lorenzo Pieralisi @ 2020-09-29 15:13 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, kernel-team, kvmarm, linux-arm-kernel

On Thu, Sep 03, 2020 at 04:26:09PM +0100, Marc Zyngier wrote:

[...]

> +static void __rvic_sync_hcr(struct kvm_vcpu *vcpu, struct rvic *rvic,
> +			    bool was_signaling)
> +{
> +	struct kvm_vcpu *target = kvm_rvic_to_vcpu(rvic);
> +	bool signal = __rvic_can_signal(rvic);
> +
> +	/* We're hitting our own rVIC: update HCR_VI locally */
> +	if (vcpu == target) {
> +		if (signal)
> +			*vcpu_hcr(vcpu) |= HCR_VI;
> +		else
> +			*vcpu_hcr(vcpu) &= ~HCR_VI;
> +
> +		return;
> +	}
> +
> +	/*
> +	 * Remote rVIC case:
> +	 *
> +	 * We kick even if the interrupt disappears, as ISR_EL1.I must
> +	 * always reflect the state of the rVIC. This forces a reload
> +	 * of the vcpu state, making it consistent.

Forgive me the question but this is unclear to me. IIUC here we do _not_
want to change the target_vcpu.hcr and we force a kick to make sure it
syncs the hcr (so the rvic) state on its own upon exit. Is that correct ?

Furthermore, I think it would be extremely useful to elaborate (ie
rework the comment) further on ISR_EL1.I and how it is linked to this
code path - I think it is key to understanding it.

Thanks,
Lorenzo

> +	 *
> +	 * This avoids modifying the target's own copy of HCR_EL2, as
> +	 * we are in a cross-vcpu call, and changing it from under its
> +	 * feet is dodgy.
> +	 */
> +	if (was_signaling != signal)
> +		__rvic_kick_vcpu(target);
> +}
> +
> +static void rvic_version(struct kvm_vcpu *vcpu)
> +{
> +	/* ALP0.3 is the name of the game */
> +	smccc_set_retval(vcpu, RVIC_STATUS_SUCCESS, RVIC_VERSION(0, 3), 0, 0);
> +}
> +
> +static void rvic_info(struct kvm_vcpu *vcpu)
> +{
> +	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +	unsigned long what = smccc_get_arg1(vcpu);
> +	unsigned long a0, a1;
> +
> +	switch (what) {
> +	case RVIC_INFO_KEY_NR_TRUSTED_INTERRUPTS:
> +		a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
> +		a1 = rvic->nr_trusted;
> +		break;
> +	case RVIC_INFO_KEY_NR_UNTRUSTED_INTERRUPTS:
> +		a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
> +		a1 = rvic_nr_untrusted(rvic);
> +		break;
> +	default:
> +		a0 = RVIx_STATUS_PACK(RVIC_STATUS_ERROR_PARAMETER, 0);
> +		a1 = 0;
> +		break;
> +	}
> +
> +	smccc_set_retval(vcpu, a0, a1, 0, 0);
> +}
> +
> +static void rvic_enable(struct kvm_vcpu *vcpu)
> +{
> +	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +	unsigned long flags;
> +	bool was_signaling;
> +
> +	spin_lock_irqsave(&rvic->lock, flags);
> +
> +	was_signaling = __rvic_can_signal(rvic);
> +	__rvic_enable(rvic);
> +	__rvic_sync_hcr(vcpu, rvic, was_signaling);
> +
> +	spin_unlock_irqrestore(&rvic->lock, flags);
> +
> +	smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0),
> +			 0, 0, 0);
> +}
> +
> +static void rvic_disable(struct kvm_vcpu *vcpu)
> +{
> +	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +	unsigned long flags;
> +	bool was_signaling;
> +
> +	spin_lock_irqsave(&rvic->lock, flags);
> +
> +	was_signaling = __rvic_can_signal(rvic);
> +	__rvic_disable(rvic);
> +	__rvic_sync_hcr(vcpu, rvic, was_signaling);
> +
> +	spin_unlock_irqrestore(&rvic->lock, flags);
> +
> +	smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0),
> +			 0, 0, 0);
> +}
> +
> +typedef void (*rvic_action_fn_t)(struct rvic *, unsigned int);
> +
> +static int validate_rvic_call(struct kvm_vcpu *vcpu, struct rvic **rvicp,
> +			      unsigned int *intidp)
> +{
> +	unsigned long mpidr = smccc_get_arg1(vcpu);
> +	unsigned int intid = smccc_get_arg2(vcpu);
> +	struct kvm_vcpu *target;
> +	struct rvic *rvic;
> +
> +	/* FIXME: The spec distinguishes between invalid MPIDR and invalid CPU */
> +
> +	target = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
> +	if (!target) {
> +		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_INVALID_CPU, 0),
> +				 0, 0, 0);
> +		return -1;
> +	}
> +
> +	rvic = kvm_vcpu_to_rvic(target);
> +	if (intid >= rvic->nr_total) {
> +		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_ERROR_PARAMETER, 1),
> +				 0, 0, 0);
> +		return -1;
> +	}
> +
> +	*rvicp = rvic;
> +	*intidp = intid;
> +
> +	return 0;
> +}
> +
> +static void __rvic_action(struct kvm_vcpu *vcpu, rvic_action_fn_t action,
> +			  bool check_enabled)
> +{
> +	struct rvic *rvic;
> +	unsigned long a0;
> +	unsigned long flags;
> +	int intid;
> +
> +	if (validate_rvic_call(vcpu, &rvic, &intid))
> +		return;
> +
> +	spin_lock_irqsave(&rvic->lock, flags);
> +
> +	if (unlikely(check_enabled && !__rvic_is_enabled(rvic))) {
> +		a0 = RVIx_STATUS_PACK(RVIC_STATUS_DISABLED, 0);
> +	} else {
> +		bool was_signaling = __rvic_can_signal(rvic);
> +		action(rvic, intid);
> +		__rvic_sync_hcr(vcpu, rvic, was_signaling);
> +		a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
> +	}
> +
> +	spin_unlock_irqrestore(&rvic->lock, flags);
> +
> +	smccc_set_retval(vcpu, a0, 0, 0, 0);
> +}
> +
> +static void rvic_set_masked(struct kvm_vcpu *vcpu)
> +{
> +	__rvic_action(vcpu, __rvic_set_masked, false);
> +}
> +
> +static void rvic_clear_masked(struct kvm_vcpu *vcpu)
> +{
> +	__rvic_action(vcpu, __rvic_clear_masked, false);
> +}
> +
> +static void rvic_clear_pending(struct kvm_vcpu *vcpu)
> +{
> +	__rvic_action(vcpu, __rvic_clear_pending, false);
> +}
> +
> +static void rvic_signal(struct kvm_vcpu *vcpu)
> +{
> +	__rvic_action(vcpu, __rvic_set_pending, true);
> +}
> +
> +static void rvic_is_pending(struct kvm_vcpu *vcpu)
> +{
> +	unsigned long flags;
> +	struct rvic *rvic;
> +	int intid;
> +	bool res;
> +
> +	if (validate_rvic_call(vcpu, &rvic, &intid))
> +		return;
> +
> +	spin_lock_irqsave(&rvic->lock, flags);
> +
> +	res = __rvic_is_pending(rvic, intid);
> +
> +	spin_unlock_irqrestore(&rvic->lock, flags);
> +
> +	smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0),
> +			 res, 0, 0);
> +}
> +
> +/*
> + * Ack and Resample are the only "interesting" operations that are
> + * strictly per-CPU.
> + */
> +static void rvic_acknowledge(struct kvm_vcpu *vcpu)
> +{
> +	unsigned long a0, a1;
> +	unsigned long flags;
> +	unsigned int intid;
> +	struct rvic *rvic;
> +
> +	rvic = kvm_vcpu_to_rvic(vcpu);
> +
> +	spin_lock_irqsave(&rvic->lock, flags);
> +
> +	if (unlikely(!__rvic_is_enabled(rvic))) {
> +		a0 = RVIx_STATUS_PACK(RVIC_STATUS_DISABLED, 0);
> +		a1 = 0;
> +	} else {
> +		intid = __rvic_ack(rvic);
> +		__rvic_sync_hcr(vcpu, rvic, true);
> +		if (unlikely(intid >= rvic->nr_total)) {
> +			a0 = RVIx_STATUS_PACK(RVIC_STATUS_NO_INTERRUPTS, 0);
> +			a1 = 0;
> +		} else {
> +			a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
> +			a1 = intid;
> +		}
> +	}
> +
> +	spin_unlock_irqrestore(&rvic->lock, flags);
> +
> +	smccc_set_retval(vcpu, a0, a1, 0, 0);
> +}
> +
> +static void rvic_resample(struct kvm_vcpu *vcpu)
> +{
> +	unsigned int intid = smccc_get_arg1(vcpu);
> +	unsigned long flags;
> +	unsigned long a0;
> +	struct rvic *rvic;
> +
> +	rvic = kvm_vcpu_to_rvic(vcpu);
> +
> +	spin_lock_irqsave(&rvic->lock, flags);
> +
> +	if (unlikely(intid >= rvic->nr_trusted)) {
> +		a0 = RVIx_STATUS_PACK(RVIC_STATUS_ERROR_PARAMETER, 0);
> +	} else {
> +		__rvic_resample(rvic, intid);
> +
> +		/*
> +		 * Don't bother finding out if we were signalling, we
> +		 * will update HCR_EL2 anyway as we are guaranteed not
> +		 * to be in a cross-call.
> +		 */
> +		__rvic_sync_hcr(vcpu, rvic, true);
> +		a0 = RVIx_STATUS_PACK(RVIC_STATUS_SUCCESS, 0);
> +	}
> +
> +	spin_unlock_irqrestore(&rvic->lock, flags);
> +
> +	smccc_set_retval(vcpu, a0, 0, 0, 0);
> +}
> +
> +int kvm_rvic_handle_hcall(struct kvm_vcpu *vcpu)
> +{
> +	pr_debug("RVIC: HC %08x", (unsigned int)smccc_get_function(vcpu));
> +	switch (smccc_get_function(vcpu)) {
> +	case SMC64_RVIC_VERSION:
> +		rvic_version(vcpu);
> +		break;
> +	case SMC64_RVIC_INFO:
> +		rvic_info(vcpu);
> +		break;
> +	case SMC64_RVIC_ENABLE:
> +		rvic_enable(vcpu);
> +		break;
> +	case SMC64_RVIC_DISABLE:
> +		rvic_disable(vcpu);
> +		break;
> +	case SMC64_RVIC_SET_MASKED:
> +		rvic_set_masked(vcpu);
> +		break;
> +	case SMC64_RVIC_CLEAR_MASKED:
> +		rvic_clear_masked(vcpu);
> +		break;
> +	case SMC64_RVIC_IS_PENDING:
> +		rvic_is_pending(vcpu);
> +		break;
> +	case SMC64_RVIC_SIGNAL:
> +		rvic_signal(vcpu);
> +		break;
> +	case SMC64_RVIC_CLEAR_PENDING:
> +		rvic_clear_pending(vcpu);
> +		break;
> +	case SMC64_RVIC_ACKNOWLEDGE:
> +		rvic_acknowledge(vcpu);
> +		break;
> +	case SMC64_RVIC_RESAMPLE:
> +		rvic_resample(vcpu);
> +		break;
> +	default:
> +		smccc_set_retval(vcpu, SMCCC_RET_NOT_SUPPORTED, 0, 0, 0);
> +		break;
> +	}
> +
> +	return 1;
> +}
> +
> +static void rvid_version(struct kvm_vcpu *vcpu)
> +{
> +	/* ALP0.3 is the name of the game */
> +	smccc_set_retval(vcpu, RVID_STATUS_SUCCESS, RVID_VERSION(0, 3), 0, 0);
> +}
> +
> +static void rvid_map(struct kvm_vcpu *vcpu)
> +{
> +	unsigned long input = smccc_get_arg1(vcpu);
> +	unsigned long mpidr = smccc_get_arg2(vcpu);
> +	unsigned int intid = smccc_get_arg3(vcpu);
> +	unsigned long flags;
> +	struct rvic_vm_data *data;
> +	struct kvm_vcpu *target;
> +
> +	data = vcpu->kvm->arch.irqchip_data;
> +
> +	if (input > rvic_nr_untrusted(data)) {
> +		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVID_STATUS_ERROR_PARAMETER, 0),
> +				 0, 0, 0);
> +		return;
> +	}
> +
> +	/* FIXME: different error from RVIC. Why? */
> +	target = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
> +	if (!target) {
> +		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVID_STATUS_ERROR_PARAMETER, 1),
> +				 0, 0, 0);
> +		return;
> +	}
> +
> +	if (intid < data->nr_trusted || intid >= data->nr_total) {
> +		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVID_STATUS_ERROR_PARAMETER, 2),
> +				 0, 0, 0);
> +		return;
> +	}
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +	data->rvid_map[input].target_vcpu	= target->vcpu_id;
> +	data->rvid_map[input].intid		= intid;
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	smccc_set_retval(vcpu, 0, 0, 0, 0);
> +}
> +
> +static void rvid_unmap(struct kvm_vcpu *vcpu)
> +{
> +	unsigned long input = smccc_get_arg1(vcpu);
> +	unsigned long flags;
> +	struct rvic_vm_data *data;
> +
> +	data = vcpu->kvm->arch.irqchip_data;
> +
> +	if (input > rvic_nr_untrusted(data)) {
> +		smccc_set_retval(vcpu, RVIx_STATUS_PACK(RVID_STATUS_ERROR_PARAMETER, 0),
> +				 0, 0, 0);
> +		return;
> +	}
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +	data->rvid_map[input].target_vcpu	= 0;
> +	data->rvid_map[input].intid		= 0;
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	smccc_set_retval(vcpu, 0, 0, 0, 0);
> +}
> +
> +int kvm_rvid_handle_hcall(struct kvm_vcpu *vcpu)
> +{
> +	pr_debug("RVID: HC %08x", (unsigned int)smccc_get_function(vcpu));
> +	switch (smccc_get_function(vcpu)) {
> +	case SMC64_RVID_VERSION:
> +		rvid_version(vcpu);
> +		break;
> +	case SMC64_RVID_MAP:
> +		rvid_map(vcpu);
> +		break;
> +	case SMC64_RVID_UNMAP:
> +		rvid_unmap(vcpu);
> +		break;
> +	default:
> +		smccc_set_retval(vcpu, SMCCC_RET_NOT_SUPPORTED, 0, 0, 0);
> +		break;
> +	}
> +
> +	return 1;
> +}
> +
> +/*
> + * KVM internal interface to the rVIC
> + */
> +
> +/* This *must* be called from the vcpu thread */
> +static void rvic_flush_signaling_state(struct kvm_vcpu *vcpu)
> +{
> +	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&rvic->lock, flags);
> +
> +	__rvic_sync_hcr(vcpu, rvic, true);
> +
> +	spin_unlock_irqrestore(&rvic->lock, flags);
> +}
> +
> +/* This can be called from any context */
> +static void rvic_vcpu_inject_irq(struct kvm_vcpu *vcpu, unsigned int intid,
> +				 bool level)
> +{
> +	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +	unsigned long flags;
> +	bool prev;
> +
> +	spin_lock_irqsave(&rvic->lock, flags);
> +
> +	if (WARN_ON(intid >= rvic->nr_total))
> +		goto out;
> +
> +	/*
> +	 * Although really ugly, this should be safe as we hold the
> +	 * rvic lock, and the only path that uses this information is
> +	 * resample, which takes this lock too.
> +	 */
> +	if (!rvic->irqs[intid].get_line_level)
> +		rvic->irqs[intid].line_level = level;
> +
> +	if (level) {
> +		prev = __rvic_can_signal(rvic);
> +		__rvic_set_pending(rvic, intid);
> +		if (prev != __rvic_can_signal(rvic))
> +			__rvic_kick_vcpu(vcpu);
> +	}
> +out:
> +	spin_unlock_irqrestore(&rvic->lock, flags);
> +}
> +
> +static int rvic_inject_irq(struct kvm *kvm, unsigned int cpu,
> +			   unsigned int intid, bool level, void *owner)
> +{
> +	struct kvm_vcpu *vcpu = kvm_get_vcpu(kvm, cpu);
> +	struct rvic *rvic;
> +
> +	if (unlikely(!vcpu))
> +		return -EINVAL;
> +
> +	rvic = kvm_vcpu_to_rvic(vcpu);
> +	if (unlikely(intid >= rvic->nr_total))
> +		return -EINVAL;
> +
> +	/* Ignore interrupt owner for now */
> +	rvic_vcpu_inject_irq(vcpu, intid, level);
> +	return 0;
> +}
> +
> +static int rvic_inject_userspace_irq(struct kvm *kvm, unsigned int type,
> +				     unsigned int cpu,
> +				     unsigned int intid, bool level)
> +{
> +	struct rvic_vm_data *data = kvm->arch.irqchip_data;
> +	unsigned long flags;
> +	u16 output;
> +
> +	switch (type) {
> +	case KVM_ARM_IRQ_TYPE_SPI:
> +		/*
> +		 * Userspace can only inject interrupts that are
> +		 * translated by the rvid, so the cpu parameter is
> +		 * irrelevant and we override it when resolving the
> +		 * translation.
> +		 */
> +		if (intid >= rvic_nr_untrusted(data))
> +			return -EINVAL;
> +
> +		spin_lock_irqsave(&data->lock, flags);
> +		output = data->rvid_map[intid].intid;
> +		cpu = data->rvid_map[intid].target_vcpu;
> +		spin_unlock_irqrestore(&data->lock, flags);
> +
> +		/* Silently ignore unmapped interrupts */
> +		if (output < data->nr_trusted)
> +			return 0;
> +
> +		return rvic_inject_irq(kvm, cpu, output, level, NULL);
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int rvic_vcpu_init(struct kvm_vcpu *vcpu)
> +{
> +	struct rvic_vm_data *data = vcpu->kvm->arch.irqchip_data;
> +	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +	int i;
> +
> +	/* irqchip not ready yet, we will come back later */
> +	if (!data)
> +		return 0;
> +
> +	if (WARN_ON(rvic->irqs))
> +		return -EINVAL;
> +
> +	spin_lock_init(&rvic->lock);
> +	INIT_LIST_HEAD(&rvic->delivery);
> +	rvic->nr_trusted	= data->nr_trusted;
> +	rvic->nr_total		= data->nr_total;
> +	rvic->enabled		= false;
> +
> +	rvic->irqs = kcalloc(rvic->nr_total, sizeof(*rvic->irqs), GFP_ATOMIC);
> +	if (!rvic->irqs)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < rvic->nr_total; i++) {
> +		struct rvic_irq *irq = &rvic->irqs[i];
> +
> +		spin_lock_init(&irq->lock);
> +		INIT_LIST_HEAD(&irq->delivery_entry);
> +		irq->get_line_level	= NULL;
> +		irq->intid		= i;
> +		irq->host_irq		= 0;
> +		irq->pending		= false;
> +		irq->masked		= true;
> +		irq->line_level		= false;
> +	}
> +
> +	return 0;
> +}
> +
> +static void rvic_destroy(struct kvm *kvm)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int i;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +
> +		INIT_LIST_HEAD(&rvic->delivery);
> +		kfree(rvic->irqs);
> +		rvic->irqs = NULL;
> +	}
> +
> +	mutex_unlock(&kvm->lock);
> +}
> +
> +static int rvic_pending_irq(struct kvm_vcpu *vcpu)
> +{
> +	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +	unsigned long flags;
> +	bool res;
> +
> +	spin_lock_irqsave(&rvic->lock, flags);
> +	res = __rvic_can_signal(rvic);
> +	spin_unlock_irqrestore(&rvic->lock, flags);
> +
> +	return res;
> +}
> +
> +static int rvic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
> +			     u32 intid, bool (*get_line_level)(int))
> +{
> +	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&irq->lock, flags);
> +	irq->host_irq = host_irq;
> +	irq->get_line_level = get_line_level;
> +	spin_unlock_irqrestore(&irq->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int rvic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int intid)
> +{
> +	struct rvic *rvic = kvm_vcpu_to_rvic(vcpu);
> +	struct rvic_irq *irq = rvic_get_irq(rvic, intid);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&irq->lock, flags);
> +	irq->host_irq = 0;
> +	irq->get_line_level = NULL;
> +	spin_unlock_irqrestore(&irq->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int rvic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
> +			      struct kvm *kvm, int irq_source_id,
> +			      int level, bool line_status)
> +{
> +	/* Abuse the userspace interface to perform the routing*/
> +	return rvic_inject_userspace_irq(kvm, KVM_ARM_IRQ_TYPE_SPI, 0,
> +					 e->irqchip.pin, level);
> +}
> +
> +static int rvic_set_msi(struct kvm_kernel_irq_routing_entry *e,
> +			struct kvm *kvm, int irq_source_id,
> +			int level, bool line_status)
> +{
> +	return -ENODEV;
> +}
> +
> +static int rvic_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
> +				 struct kvm *kvm, int irq_source_id,
> +				 int level, bool line_status)
> +{
> +	if (e->type != KVM_IRQ_ROUTING_IRQCHIP)
> +		return -EWOULDBLOCK;
> +
> +	return rvic_irqfd_set_irq(e, kvm, irq_source_id, level, line_status);
> +}
> +
> +static const struct kvm_irqchip_flow rvic_irqchip_flow = {
> +	.irqchip_destroy		= rvic_destroy,
> +	.irqchip_vcpu_init		= rvic_vcpu_init,
> +	/* Nothing to do on block/unblock */
> +	/* Nothing to do on load/put */
> +	.irqchip_vcpu_pending_irq	= rvic_pending_irq,
> +	.irqchip_vcpu_flush_hwstate	= rvic_flush_signaling_state,
> +	/* Nothing tp do on sync_hwstate */
> +	.irqchip_inject_irq		= rvic_inject_irq,
> +	.irqchip_inject_userspace_irq	= rvic_inject_userspace_irq,
> +	/* No reset_mapped_irq as we allow spurious interrupts */
> +	.irqchip_map_phys_irq		= rvic_map_phys_irq,
> +	.irqchip_unmap_phys_irq		= rvic_unmap_phys_irq,
> +	.irqchip_irqfd_set_irq		= rvic_irqfd_set_irq,
> +	.irqchip_set_msi		= rvic_set_msi,
> +	.irqchip_set_irq_inatomic	= rvic_set_irq_inatomic,
> +};
> +
> +static int rvic_setup_default_irq_routing(struct kvm *kvm)
> +{
> +	struct rvic_vm_data *data = kvm->arch.irqchip_data;
> +	unsigned int nr = rvic_nr_untrusted(data);
> +	struct kvm_irq_routing_entry *entries;
> +	int i, ret;
> +
> +	entries = kcalloc(nr, sizeof(*entries), GFP_KERNEL);
> +	if (!entries)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < nr; i++) {
> +		entries[i].gsi = i;
> +		entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
> +		entries[i].u.irqchip.irqchip = 0;
> +		entries[i].u.irqchip.pin = i;
> +	}
> +	ret = kvm_set_irq_routing(kvm, entries, nr, 0);
> +	kfree(entries);
> +	return ret;
> +}
> +
> +/* Device management */
> +static int rvic_device_create(struct kvm_device *dev, u32 type)
> +{
> +	struct kvm *kvm = dev->kvm;
> +	struct kvm_vcpu *vcpu;
> +	int i, ret;
> +
> +	if (irqchip_in_kernel(kvm))
> +		return -EEXIST;
> +
> +	ret = -EBUSY;
> +	if (!lock_all_vcpus(kvm))
> +		return ret;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (vcpu->arch.has_run_once)
> +			goto out_unlock;
> +	}
> +
> +	ret = 0;
> +
> +	/*
> +	 * The good thing about not having any HW is that you don't
> +	 * get the limitations of the HW...
> +	 */
> +	kvm->arch.max_vcpus		= KVM_MAX_VCPUS;
> +	kvm->arch.irqchip_type		= IRQCHIP_RVIC;
> +	kvm->arch.irqchip_flow		= rvic_irqchip_flow;
> +	kvm->arch.irqchip_data		= NULL;
> +
> +out_unlock:
> +	unlock_all_vcpus(kvm);
> +	return ret;
> +}
> +
> +static void rvic_device_destroy(struct kvm_device *dev)
> +{
> +	kfree(dev->kvm->arch.irqchip_data);
> +	kfree(dev);
> +}
> +
> +static int rvic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
> +{
> +	struct rvic_vm_data *data;
> +	struct kvm_vcpu *vcpu;
> +	u32 __user *uaddr, val;
> +	u16 trusted, total;
> +	int i, ret = -ENXIO;
> +
> +	mutex_lock(&dev->kvm->lock);
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_RVIC_GRP_NR_IRQS:
> +		if (attr->attr)
> +			break;
> +
> +		if (dev->kvm->arch.irqchip_data) {
> +			ret = -EBUSY;
> +			break;
> +		}
> +
> +		uaddr = (u32 __user *)(uintptr_t)attr->addr;
> +		if (get_user(val, uaddr)) {
> +			ret = -EFAULT;
> +			break;
> +		}
> +
> +		trusted = FIELD_GET(KVM_DEV_ARM_RVIC_GRP_NR_TRUSTED_MASK, val);
> +		total   = FIELD_GET(KVM_DEV_ARM_RVIC_GRP_NR_TOTAL_MASK, val);
> +		if (total < trusted || trusted < 32 || total < 64 ||
> +		    trusted % 32 || total % 32 || total > 2048) {
> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		data = kzalloc(struct_size(data, rvid_map, (total - trusted)),
> +			       GFP_KERNEL);
> +		if (!data) {
> +			ret = -ENOMEM;
> +			break;
> +		}
> +
> +		data->nr_trusted = trusted;
> +		data->nr_total = total;
> +		spin_lock_init(&data->lock);
> +		/* Default to no mapping */
> +		for (i = 0; i < (total - trusted); i++) {
> +			/*
> +			 * an intid < nr_trusted is invalid as the
> +			 * result of a translation through the rvid,
> +			 * hence the input in unmapped.
> +			 */
> +			data->rvid_map[i].target_vcpu = 0;
> +			data->rvid_map[i].intid = 0;
> +		}
> +
> +		dev->kvm->arch.irqchip_data = data;
> +
> +		ret = 0;
> +		break;
> +
> +	case KVM_DEV_ARM_RVIC_GRP_INIT:
> +		if (attr->attr)
> +			break;
> +
> +		if (!dev->kvm->arch.irqchip_data)
> +			break;
> +
> +		ret = 0;
> +
> +		/* Init the rvic on any already created vcpu */
> +		kvm_for_each_vcpu(i, vcpu, dev->kvm) {
> +			ret = rvic_vcpu_init(vcpu);
> +			if (ret)
> +				break;
> +		}
> +
> +		if (!ret)
> +			ret = rvic_setup_default_irq_routing(dev->kvm);
> +		if (!ret)
> +			dev->kvm->arch.irqchip_finalized = true;
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	mutex_unlock(&dev->kvm->lock);
> +
> +	return ret;
> +}
> +
> +static int rvic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
> +{
> +	struct rvic_vm_data *data;
> +	u32 __user *uaddr, val;
> +	int ret = -ENXIO;
> +
> +	mutex_lock(&dev->kvm->lock);
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_RVIC_GRP_NR_IRQS:
> +		if (attr->attr)
> +			break;
> +
> +		data = dev->kvm->arch.irqchip_data;
> +		if (!data)
> +			break;
> +
> +		val  = FIELD_PREP(KVM_DEV_ARM_RVIC_GRP_NR_TRUSTED_MASK,
> +					 data->nr_trusted);
> +		val |= FIELD_PREP(KVM_DEV_ARM_RVIC_GRP_NR_TOTAL_MASK,
> +					 data->nr_total);
> +
> +		uaddr = (u32 __user *)(uintptr_t)attr->addr;
> +		ret = put_user(val, uaddr);
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	mutex_unlock(&dev->kvm->lock);
> +
> +	return ret;
> +}
> +
> +static int rvic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
> +{
> +	int ret = -ENXIO;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_RVIC_GRP_NR_IRQS:
> +	case KVM_DEV_ARM_RVIC_GRP_INIT:
> +		if (attr->attr)
> +			break;
> +		ret = 0;
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct kvm_device_ops rvic_dev_ops = {
> +	.name		= "kvm-arm-rvic",
> +	.create		= rvic_device_create,
> +	.destroy	= rvic_device_destroy,
> +	.set_attr	= rvic_set_attr,
> +	.get_attr	= rvic_get_attr,
> +	.has_attr	= rvic_has_attr,
> +};
> +
> +int kvm_register_rvic_device(void)
> +{
> +	return kvm_register_device_ops(&rvic_dev_ops, KVM_DEV_TYPE_ARM_RVIC);
> +}
> diff --git a/include/kvm/arm_rvic.h b/include/kvm/arm_rvic.h
> new file mode 100644
> index 000000000000..9e67a83fa384
> --- /dev/null
> +++ b/include/kvm/arm_rvic.h
> @@ -0,0 +1,41 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * rVIC/rVID PV interrupt controller implementation for KVM/arm64.
> + *
> + * Copyright 2020 Google LLC.
> + * Author: Marc Zyngier <maz@kernel.org>
> + */
> +
> +#ifndef __KVM_ARM_RVIC_H__
> +#define __KVM_ARM_RVIC_H__
> +
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +
> +struct kvm_vcpu;
> +
> +struct rvic_irq {
> +	spinlock_t		lock;
> +	struct list_head	delivery_entry;
> +	bool			(*get_line_level)(int intid);
> +	unsigned int		intid;
> +	unsigned int		host_irq;
> +	bool			pending;
> +	bool			masked;
> +	bool			line_level; /* If get_line_level == NULL */
> +};
> +
> +struct rvic {
> +	spinlock_t		lock;
> +	struct list_head	delivery;
> +	struct rvic_irq		*irqs;
> +	unsigned int		nr_trusted;
> +	unsigned int		nr_total;
> +	bool			enabled;
> +};
> +
> +int kvm_rvic_handle_hcall(struct kvm_vcpu *vcpu);
> +int kvm_rvid_handle_hcall(struct kvm_vcpu *vcpu);
> +int kvm_register_rvic_device(void);
> +
> +#endif
> diff --git a/include/linux/irqchip/irq-rvic.h b/include/linux/irqchip/irq-rvic.h
> index 4545c1e89741..b188773729fb 100644
> --- a/include/linux/irqchip/irq-rvic.h
> +++ b/include/linux/irqchip/irq-rvic.h
> @@ -57,6 +57,8 @@
>  #define SMC64_RVIC_ACKNOWLEDGE		SMC64_RVIC_FN(9)
>  #define SMC64_RVIC_RESAMPLE		SMC64_RVIC_FN(10)
>  
> +#define SMC64_RVIC_LAST			SMC64_RVIC_RESAMPLE
> +
>  #define RVIC_INFO_KEY_NR_TRUSTED_INTERRUPTS	0
>  #define RVIC_INFO_KEY_NR_UNTRUSTED_INTERRUPTS	1
>  
> @@ -82,6 +84,8 @@
>  #define SMC64_RVID_MAP			SMC64_RVID_FN(1)
>  #define SMC64_RVID_UNMAP		SMC64_RVID_FN(2)
>  
> +#define SMC64_RVID_LAST			SMC64_RVID_UNMAP
> +
>  #define RVID_VERSION(M, m)		RVIx_VERSION((M), (m))
>  
>  #define RVID_VERSION_MAJOR(v)		RVIx_VERSION_MAJOR((v))
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index f6d86033c4fa..6d245d2dc9e6 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1264,6 +1264,8 @@ enum kvm_device_type {
>  #define KVM_DEV_TYPE_XIVE		KVM_DEV_TYPE_XIVE
>  	KVM_DEV_TYPE_ARM_PV_TIME,
>  #define KVM_DEV_TYPE_ARM_PV_TIME	KVM_DEV_TYPE_ARM_PV_TIME
> +	KVM_DEV_TYPE_ARM_RVIC,
> +#define KVM_DEV_TYPE_ARM_RVIC		KVM_DEV_TYPE_ARM_RVIC
>  	KVM_DEV_TYPE_MAX,
>  };
>  
> -- 
> 2.27.0
> 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation
  2020-09-29 15:13   ` Lorenzo Pieralisi
@ 2020-09-29 15:27     ` Marc Zyngier
  2020-09-29 16:09       ` Lorenzo Pieralisi
  0 siblings, 1 reply; 35+ messages in thread
From: Marc Zyngier @ 2020-09-29 15:27 UTC (permalink / raw)
  To: Lorenzo Pieralisi; +Cc: kvm, kernel-team, kvmarm, linux-arm-kernel

Hi Lorenzo,

On 2020-09-29 16:13, Lorenzo Pieralisi wrote:
> On Thu, Sep 03, 2020 at 04:26:09PM +0100, Marc Zyngier wrote:
> 
> [...]
> 
>> +static void __rvic_sync_hcr(struct kvm_vcpu *vcpu, struct rvic *rvic,
>> +			    bool was_signaling)
>> +{
>> +	struct kvm_vcpu *target = kvm_rvic_to_vcpu(rvic);
>> +	bool signal = __rvic_can_signal(rvic);
>> +
>> +	/* We're hitting our own rVIC: update HCR_VI locally */
>> +	if (vcpu == target) {
>> +		if (signal)
>> +			*vcpu_hcr(vcpu) |= HCR_VI;
>> +		else
>> +			*vcpu_hcr(vcpu) &= ~HCR_VI;
>> +
>> +		return;
>> +	}
>> +
>> +	/*
>> +	 * Remote rVIC case:
>> +	 *
>> +	 * We kick even if the interrupt disappears, as ISR_EL1.I must
>> +	 * always reflect the state of the rVIC. This forces a reload
>> +	 * of the vcpu state, making it consistent.
> 
> Forgive me the question but this is unclear to me. IIUC here we do 
> _not_
> want to change the target_vcpu.hcr and we force a kick to make sure it
> syncs the hcr (so the rvic) state on its own upon exit. Is that correct 
> ?

This is indeed correct. Changing the vcpu's hcr is racy as we sometimes
update it on vcpu exit, so directly updating this field would require
introducing atomic accesses between El1 and EL2. Not happening.

Instead, we force the vcpu to reload its own state as it *reenters*
the guest (and not on exit). This way, no locking, no cmpxchg, 
everything
is still single threaded.

> Furthermore, I think it would be extremely useful to elaborate (ie
> rework the comment) further on ISR_EL1.I and how it is linked to this
> code path - I think it is key to understanding it.

I'm not really sure what to add here, apart from paraphrasing the ARM 
ARM.
ISR_EL1 always represents the interrupt input to the CPU, virtual or 
not,
and we must honor this requirements by making any change of output of
the rVIC directly observable (i.e. update HCR_EL2.VI).

         M.
-- 
Jazz is not dead. It just smells funny...
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation
  2020-09-29 15:27     ` Marc Zyngier
@ 2020-09-29 16:09       ` Lorenzo Pieralisi
  0 siblings, 0 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2020-09-29 16:09 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, kernel-team, kvmarm, linux-arm-kernel

On Tue, Sep 29, 2020 at 04:27:45PM +0100, Marc Zyngier wrote:
> Hi Lorenzo,
> 
> On 2020-09-29 16:13, Lorenzo Pieralisi wrote:
> > On Thu, Sep 03, 2020 at 04:26:09PM +0100, Marc Zyngier wrote:
> > 
> > [...]
> > 
> > > +static void __rvic_sync_hcr(struct kvm_vcpu *vcpu, struct rvic *rvic,
> > > +			    bool was_signaling)
> > > +{
> > > +	struct kvm_vcpu *target = kvm_rvic_to_vcpu(rvic);
> > > +	bool signal = __rvic_can_signal(rvic);
> > > +
> > > +	/* We're hitting our own rVIC: update HCR_VI locally */
> > > +	if (vcpu == target) {
> > > +		if (signal)
> > > +			*vcpu_hcr(vcpu) |= HCR_VI;
> > > +		else
> > > +			*vcpu_hcr(vcpu) &= ~HCR_VI;
> > > +
> > > +		return;
> > > +	}
> > > +
> > > +	/*
> > > +	 * Remote rVIC case:
> > > +	 *
> > > +	 * We kick even if the interrupt disappears, as ISR_EL1.I must
> > > +	 * always reflect the state of the rVIC. This forces a reload
> > > +	 * of the vcpu state, making it consistent.
> > 
> > Forgive me the question but this is unclear to me. IIUC here we do _not_
> > want to change the target_vcpu.hcr and we force a kick to make sure it
> > syncs the hcr (so the rvic) state on its own upon exit. Is that correct
> > ?
> 
> This is indeed correct. Changing the vcpu's hcr is racy as we sometimes
> update it on vcpu exit, so directly updating this field would require
> introducing atomic accesses between El1 and EL2. Not happening.
> 
> Instead, we force the vcpu to reload its own state as it *reenters*
> the guest (and not on exit). This way, no locking, no cmpxchg, everything
> is still single threaded.
> 
> > Furthermore, I think it would be extremely useful to elaborate (ie
> > rework the comment) further on ISR_EL1.I and how it is linked to this
> > code path - I think it is key to understanding it.
> 
> I'm not really sure what to add here, apart from paraphrasing the ARM ARM.
> ISR_EL1 always represents the interrupt input to the CPU, virtual or not,
> and we must honor this requirements by making any change of output of
> the rVIC directly observable (i.e. update HCR_EL2.VI).

Ok got it. Basically we kick the target_vcpu because there is a change
in its IRQ input signal that has to be signalled (by updating the
HCR_EL2.VI that in turns updates the ISR_EL1.I). I read the comment as
if we don't care about the target_vcpu.hcr_el2 update and was struggling
to understand the whole code path.

Back to reading the code (properly :)).

Thanks,
Lorenzo
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2020-09-29 16:09 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-03 15:25 [PATCH 00/23] KVM: arm64: rVIC/rVID PV interrupt controller Marc Zyngier
2020-09-03 15:25 ` [PATCH 01/23] irqchip: Add Reduced Virtual Interrupt Controller driver Marc Zyngier
2020-09-03 15:25 ` [PATCH 02/23] irqchip/rvic: Add support for untrusted interrupt allocation Marc Zyngier
2020-09-04 13:40   ` Jonathan Cameron
2020-09-03 15:25 ` [PATCH 03/23] irqchip: Add Reduced Virtual Interrupt Distributor support Marc Zyngier
2020-09-04 13:56   ` Jonathan Cameron
2020-09-03 15:25 ` [PATCH 04/23] irqchip/rvid: Add PCI MSI support Marc Zyngier
2020-09-04 14:15   ` Jonathan Cameron
2020-09-05 13:08     ` Marc Zyngier
2020-09-03 15:25 ` [PATCH 05/23] KVM: arm64: Move GIC model out of the distributor Marc Zyngier
2020-09-04 14:37   ` Jonathan Cameron
2020-09-03 15:25 ` [PATCH 06/23] KVM: arm64: vgic-v3: Move early init to kvm_vgic_create() Marc Zyngier
2020-09-03 15:25 ` [PATCH 07/23] KVM: arm64: Add irqchip callback structure to kvm_arch Marc Zyngier
2020-09-03 15:25 ` [PATCH 08/23] KVM: arm64: Move kvm_vgic_destroy to kvm_irqchip_flow Marc Zyngier
2020-09-03 15:25 ` [PATCH 09/23] KVM: arm64: Move kvm_vgic_vcpu_init() to irqchip_flow Marc Zyngier
2020-09-03 15:25 ` [PATCH 10/23] KVM: arm64: Move kvm_vgic_vcpu_[un]blocking() " Marc Zyngier
2020-09-03 15:25 ` [PATCH 11/23] KVM: arm64: Move kvm_vgic_vcpu_load/put() " Marc Zyngier
2020-09-03 15:25 ` [PATCH 12/23] KVM: arm64: Move kvm_vgic_vcpu_pending_irq() " Marc Zyngier
2020-09-04 14:57   ` Jonathan Cameron
2020-09-03 15:26 ` [PATCH 13/23] KVM: arm64: Move vgic resource mapping on first run " Marc Zyngier
2020-09-03 15:26 ` [PATCH 14/23] KVM: arm64: Move kvm_vgic_vcpu_{sync, flush}_hwstate() " Marc Zyngier
2020-09-03 15:26 ` [PATCH 15/23] KVM: arm64: nVHE: Only save/restore GICv3 state if modeling a GIC Marc Zyngier
2020-09-03 15:26 ` [PATCH 16/23] KVM: arm64: Move interrupt injection to irqchip_flow Marc Zyngier
2020-09-03 15:26 ` [PATCH 17/23] KVM: arm64: Move mapping of HW interrupts into irqchip_flow Marc Zyngier
2020-09-03 15:26 ` [PATCH 18/23] KVM: arm64: Move set_owner " Marc Zyngier
2020-09-03 15:26 ` [PATCH 19/23] KVM: arm64: Turn vgic_initialized into irqchip_finalized Marc Zyngier
2020-09-03 15:26 ` [PATCH 20/23] KVM: arm64: Move irqfd routing to irqchip_flow Marc Zyngier
2020-09-03 15:26 ` [PATCH 21/23] KVM: arm64: Tighten msis_require_devid reporting Marc Zyngier
2020-09-03 15:26 ` [PATCH 22/23] KVM: arm64: Add a rVIC/rVID in-kernel implementation Marc Zyngier
2020-09-04 16:00   ` Jonathan Cameron
2020-09-05 13:16     ` Marc Zyngier
2020-09-29 15:13   ` Lorenzo Pieralisi
2020-09-29 15:27     ` Marc Zyngier
2020-09-29 16:09       ` Lorenzo Pieralisi
2020-09-03 15:26 ` [PATCH 23/23] KVM: arm64: Add debugfs files for the rVIC/rVID implementation Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).