18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2015, 2016 ARM Ltd.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
78c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
88c2ecf20Sopenharmony_ci#include <linux/cpu.h>
98c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
108c2ecf20Sopenharmony_ci#include <kvm/arm_vgic.h>
118c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h>
128c2ecf20Sopenharmony_ci#include <asm/kvm_mmu.h>
138c2ecf20Sopenharmony_ci#include "vgic.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/*
168c2ecf20Sopenharmony_ci * Initialization rules: there are multiple stages to the vgic
178c2ecf20Sopenharmony_ci * initialization, both for the distributor and the CPU interfaces.  The basic
188c2ecf20Sopenharmony_ci * idea is that even though the VGIC is not functional or not requested from
198c2ecf20Sopenharmony_ci * user space, the critical path of the run loop can still call VGIC functions
208c2ecf20Sopenharmony_ci * that just won't do anything, without them having to check additional
218c2ecf20Sopenharmony_ci * initialization flags to ensure they don't look at uninitialized data
228c2ecf20Sopenharmony_ci * structures.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Distributor:
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * - kvm_vgic_early_init(): initialization of static data that doesn't
278c2ecf20Sopenharmony_ci *   depend on any sizing information or emulation type. No allocation
288c2ecf20Sopenharmony_ci *   is allowed there.
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * - vgic_init(): allocation and initialization of the generic data
318c2ecf20Sopenharmony_ci *   structures that depend on sizing information (number of CPUs,
328c2ecf20Sopenharmony_ci *   number of interrupts). Also initializes the vcpu specific data
338c2ecf20Sopenharmony_ci *   structures. Can be executed lazily for GICv2.
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci * CPU Interface:
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * - kvm_vgic_vcpu_init(): initialization of static data that
388c2ecf20Sopenharmony_ci *   doesn't depend on any sizing information or emulation type. No
398c2ecf20Sopenharmony_ci *   allocation is allowed there.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* EARLY INIT */
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/**
458c2ecf20Sopenharmony_ci * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
468c2ecf20Sopenharmony_ci * @kvm: The VM whose VGIC districutor should be initialized
478c2ecf20Sopenharmony_ci *
488c2ecf20Sopenharmony_ci * Only do initialization of static structures that don't require any
498c2ecf20Sopenharmony_ci * allocation or sizing information from userspace.  vgic_init() called
508c2ecf20Sopenharmony_ci * kvm_vgic_dist_init() which takes care of the rest.
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_civoid kvm_vgic_early_init(struct kvm *kvm)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dist->lpi_list_head);
578c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dist->lpi_translation_cache);
588c2ecf20Sopenharmony_ci	raw_spin_lock_init(&dist->lpi_list_lock);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* CREATION */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/**
648c2ecf20Sopenharmony_ci * kvm_vgic_create: triggered by the instantiation of the VGIC device by
658c2ecf20Sopenharmony_ci * user space, either through the legacy KVM_CREATE_IRQCHIP ioctl (v2 only)
668c2ecf20Sopenharmony_ci * or through the generic KVM_CREATE_DEVICE API ioctl.
678c2ecf20Sopenharmony_ci * irqchip_in_kernel() tells you if this function succeeded or not.
688c2ecf20Sopenharmony_ci * @kvm: kvm struct pointer
698c2ecf20Sopenharmony_ci * @type: KVM_DEV_TYPE_ARM_VGIC_V[23]
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_ciint kvm_vgic_create(struct kvm *kvm, u32 type)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	int i, ret;
748c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (irqchip_in_kernel(kvm))
778c2ecf20Sopenharmony_ci		return -EEXIST;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/*
808c2ecf20Sopenharmony_ci	 * This function is also called by the KVM_CREATE_IRQCHIP handler,
818c2ecf20Sopenharmony_ci	 * which had no chance yet to check the availability of the GICv2
828c2ecf20Sopenharmony_ci	 * emulation. So check this here again. KVM_CREATE_DEVICE does
838c2ecf20Sopenharmony_ci	 * the proper checks already.
848c2ecf20Sopenharmony_ci	 */
858c2ecf20Sopenharmony_ci	if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
868c2ecf20Sopenharmony_ci		!kvm_vgic_global_state.can_emulate_gicv2)
878c2ecf20Sopenharmony_ci		return -ENODEV;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	ret = -EBUSY;
908c2ecf20Sopenharmony_ci	if (!lock_all_vcpus(kvm))
918c2ecf20Sopenharmony_ci		return ret;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	kvm_for_each_vcpu(i, vcpu, kvm) {
948c2ecf20Sopenharmony_ci		if (vcpu->arch.has_run_once)
958c2ecf20Sopenharmony_ci			goto out_unlock;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci	ret = 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
1008c2ecf20Sopenharmony_ci		kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
1018c2ecf20Sopenharmony_ci	else
1028c2ecf20Sopenharmony_ci		kvm->arch.max_vcpus = VGIC_V3_MAX_CPUS;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (atomic_read(&kvm->online_vcpus) > kvm->arch.max_vcpus) {
1058c2ecf20Sopenharmony_ci		ret = -E2BIG;
1068c2ecf20Sopenharmony_ci		goto out_unlock;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	kvm->arch.vgic.in_kernel = true;
1108c2ecf20Sopenharmony_ci	kvm->arch.vgic.vgic_model = type;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
1158c2ecf20Sopenharmony_ci		kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
1168c2ecf20Sopenharmony_ci	else
1178c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ciout_unlock:
1208c2ecf20Sopenharmony_ci	unlock_all_vcpus(kvm);
1218c2ecf20Sopenharmony_ci	return ret;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/* INIT/DESTROY */
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/**
1278c2ecf20Sopenharmony_ci * kvm_vgic_dist_init: initialize the dist data structures
1288c2ecf20Sopenharmony_ci * @kvm: kvm struct pointer
1298c2ecf20Sopenharmony_ci * @nr_spis: number of spis, frozen by caller
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_cistatic int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
1348c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
1358c2ecf20Sopenharmony_ci	int i;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
1388c2ecf20Sopenharmony_ci	if (!dist->spis)
1398c2ecf20Sopenharmony_ci		return  -ENOMEM;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/*
1428c2ecf20Sopenharmony_ci	 * In the following code we do not take the irq struct lock since
1438c2ecf20Sopenharmony_ci	 * no other action on irq structs can happen while the VGIC is
1448c2ecf20Sopenharmony_ci	 * not initialized yet:
1458c2ecf20Sopenharmony_ci	 * If someone wants to inject an interrupt or does a MMIO access, we
1468c2ecf20Sopenharmony_ci	 * require prior initialization in case of a virtual GICv3 or trigger
1478c2ecf20Sopenharmony_ci	 * initialization when using a virtual GICv2.
1488c2ecf20Sopenharmony_ci	 */
1498c2ecf20Sopenharmony_ci	for (i = 0; i < nr_spis; i++) {
1508c2ecf20Sopenharmony_ci		struct vgic_irq *irq = &dist->spis[i];
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
1538c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&irq->ap_list);
1548c2ecf20Sopenharmony_ci		raw_spin_lock_init(&irq->irq_lock);
1558c2ecf20Sopenharmony_ci		irq->vcpu = NULL;
1568c2ecf20Sopenharmony_ci		irq->target_vcpu = vcpu0;
1578c2ecf20Sopenharmony_ci		kref_init(&irq->refcount);
1588c2ecf20Sopenharmony_ci		switch (dist->vgic_model) {
1598c2ecf20Sopenharmony_ci		case KVM_DEV_TYPE_ARM_VGIC_V2:
1608c2ecf20Sopenharmony_ci			irq->targets = 0;
1618c2ecf20Sopenharmony_ci			irq->group = 0;
1628c2ecf20Sopenharmony_ci			break;
1638c2ecf20Sopenharmony_ci		case KVM_DEV_TYPE_ARM_VGIC_V3:
1648c2ecf20Sopenharmony_ci			irq->mpidr = 0;
1658c2ecf20Sopenharmony_ci			irq->group = 1;
1668c2ecf20Sopenharmony_ci			break;
1678c2ecf20Sopenharmony_ci		default:
1688c2ecf20Sopenharmony_ci			kfree(dist->spis);
1698c2ecf20Sopenharmony_ci			dist->spis = NULL;
1708c2ecf20Sopenharmony_ci			return -EINVAL;
1718c2ecf20Sopenharmony_ci		}
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci	return 0;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/**
1778c2ecf20Sopenharmony_ci * kvm_vgic_vcpu_init() - Initialize static VGIC VCPU data
1788c2ecf20Sopenharmony_ci * structures and register VCPU-specific KVM iodevs
1798c2ecf20Sopenharmony_ci *
1808c2ecf20Sopenharmony_ci * @vcpu: pointer to the VCPU being created and initialized
1818c2ecf20Sopenharmony_ci *
1828c2ecf20Sopenharmony_ci * Only do initialization, but do not actually enable the
1838c2ecf20Sopenharmony_ci * VGIC CPU interface
1848c2ecf20Sopenharmony_ci */
1858c2ecf20Sopenharmony_ciint kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
1888c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
1898c2ecf20Sopenharmony_ci	int ret = 0;
1908c2ecf20Sopenharmony_ci	int i;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
1958c2ecf20Sopenharmony_ci	raw_spin_lock_init(&vgic_cpu->ap_list_lock);
1968c2ecf20Sopenharmony_ci	atomic_set(&vgic_cpu->vgic_v3.its_vpe.vlpi_count, 0);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/*
1998c2ecf20Sopenharmony_ci	 * Enable and configure all SGIs to be edge-triggered and
2008c2ecf20Sopenharmony_ci	 * configure all PPIs as level-triggered.
2018c2ecf20Sopenharmony_ci	 */
2028c2ecf20Sopenharmony_ci	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
2038c2ecf20Sopenharmony_ci		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&irq->ap_list);
2068c2ecf20Sopenharmony_ci		raw_spin_lock_init(&irq->irq_lock);
2078c2ecf20Sopenharmony_ci		irq->intid = i;
2088c2ecf20Sopenharmony_ci		irq->vcpu = NULL;
2098c2ecf20Sopenharmony_ci		irq->target_vcpu = vcpu;
2108c2ecf20Sopenharmony_ci		kref_init(&irq->refcount);
2118c2ecf20Sopenharmony_ci		if (vgic_irq_is_sgi(i)) {
2128c2ecf20Sopenharmony_ci			/* SGIs */
2138c2ecf20Sopenharmony_ci			irq->enabled = 1;
2148c2ecf20Sopenharmony_ci			irq->config = VGIC_CONFIG_EDGE;
2158c2ecf20Sopenharmony_ci		} else {
2168c2ecf20Sopenharmony_ci			/* PPIs */
2178c2ecf20Sopenharmony_ci			irq->config = VGIC_CONFIG_LEVEL;
2188c2ecf20Sopenharmony_ci		}
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (!irqchip_in_kernel(vcpu->kvm))
2228c2ecf20Sopenharmony_ci		return 0;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/*
2258c2ecf20Sopenharmony_ci	 * If we are creating a VCPU with a GICv3 we must also register the
2268c2ecf20Sopenharmony_ci	 * KVM io device for the redistributor that belongs to this VCPU.
2278c2ecf20Sopenharmony_ci	 */
2288c2ecf20Sopenharmony_ci	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
2298c2ecf20Sopenharmony_ci		mutex_lock(&vcpu->kvm->lock);
2308c2ecf20Sopenharmony_ci		ret = vgic_register_redist_iodev(vcpu);
2318c2ecf20Sopenharmony_ci		mutex_unlock(&vcpu->kvm->lock);
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	return ret;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic void kvm_vgic_vcpu_enable(struct kvm_vcpu *vcpu)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	if (kvm_vgic_global_state.type == VGIC_V2)
2398c2ecf20Sopenharmony_ci		vgic_v2_enable(vcpu);
2408c2ecf20Sopenharmony_ci	else
2418c2ecf20Sopenharmony_ci		vgic_v3_enable(vcpu);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci/*
2458c2ecf20Sopenharmony_ci * vgic_init: allocates and initializes dist and vcpu data structures
2468c2ecf20Sopenharmony_ci * depending on two dimensioning parameters:
2478c2ecf20Sopenharmony_ci * - the number of spis
2488c2ecf20Sopenharmony_ci * - the number of vcpus
2498c2ecf20Sopenharmony_ci * The function is generally called when nr_spis has been explicitly set
2508c2ecf20Sopenharmony_ci * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
2518c2ecf20Sopenharmony_ci * vgic_initialized() returns true when this function has succeeded.
2528c2ecf20Sopenharmony_ci * Must be called with kvm->lock held!
2538c2ecf20Sopenharmony_ci */
2548c2ecf20Sopenharmony_ciint vgic_init(struct kvm *kvm)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
2578c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu;
2588c2ecf20Sopenharmony_ci	int ret = 0, i, idx;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (vgic_initialized(kvm))
2618c2ecf20Sopenharmony_ci		return 0;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* Are we also in the middle of creating a VCPU? */
2648c2ecf20Sopenharmony_ci	if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))
2658c2ecf20Sopenharmony_ci		return -EBUSY;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* freeze the number of spis */
2688c2ecf20Sopenharmony_ci	if (!dist->nr_spis)
2698c2ecf20Sopenharmony_ci		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
2728c2ecf20Sopenharmony_ci	if (ret)
2738c2ecf20Sopenharmony_ci		goto out;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/* Initialize groups on CPUs created before the VGIC type was known */
2768c2ecf20Sopenharmony_ci	kvm_for_each_vcpu(idx, vcpu, kvm) {
2778c2ecf20Sopenharmony_ci		struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci		for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
2808c2ecf20Sopenharmony_ci			struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
2818c2ecf20Sopenharmony_ci			switch (dist->vgic_model) {
2828c2ecf20Sopenharmony_ci			case KVM_DEV_TYPE_ARM_VGIC_V3:
2838c2ecf20Sopenharmony_ci				irq->group = 1;
2848c2ecf20Sopenharmony_ci				irq->mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
2858c2ecf20Sopenharmony_ci				break;
2868c2ecf20Sopenharmony_ci			case KVM_DEV_TYPE_ARM_VGIC_V2:
2878c2ecf20Sopenharmony_ci				irq->group = 0;
2888c2ecf20Sopenharmony_ci				irq->targets = 1U << idx;
2898c2ecf20Sopenharmony_ci				break;
2908c2ecf20Sopenharmony_ci			default:
2918c2ecf20Sopenharmony_ci				ret = -EINVAL;
2928c2ecf20Sopenharmony_ci				goto out;
2938c2ecf20Sopenharmony_ci			}
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if (vgic_has_its(kvm))
2988c2ecf20Sopenharmony_ci		vgic_lpi_translation_cache_init(kvm);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/*
3018c2ecf20Sopenharmony_ci	 * If we have GICv4.1 enabled, unconditionnaly request enable the
3028c2ecf20Sopenharmony_ci	 * v4 support so that we get HW-accelerated vSGIs. Otherwise, only
3038c2ecf20Sopenharmony_ci	 * enable it if we present a virtual ITS to the guest.
3048c2ecf20Sopenharmony_ci	 */
3058c2ecf20Sopenharmony_ci	if (vgic_supports_direct_msis(kvm)) {
3068c2ecf20Sopenharmony_ci		ret = vgic_v4_init(kvm);
3078c2ecf20Sopenharmony_ci		if (ret)
3088c2ecf20Sopenharmony_ci			goto out;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	kvm_for_each_vcpu(i, vcpu, kvm)
3128c2ecf20Sopenharmony_ci		kvm_vgic_vcpu_enable(vcpu);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	ret = kvm_vgic_setup_default_irq_routing(kvm);
3158c2ecf20Sopenharmony_ci	if (ret)
3168c2ecf20Sopenharmony_ci		goto out;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	vgic_debug_init(kvm);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	dist->implementation_rev = 2;
3218c2ecf20Sopenharmony_ci	dist->initialized = true;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ciout:
3248c2ecf20Sopenharmony_ci	return ret;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic void kvm_vgic_dist_destroy(struct kvm *kvm)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
3308c2ecf20Sopenharmony_ci	struct vgic_redist_region *rdreg, *next;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	dist->ready = false;
3338c2ecf20Sopenharmony_ci	dist->initialized = false;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	kfree(dist->spis);
3368c2ecf20Sopenharmony_ci	dist->spis = NULL;
3378c2ecf20Sopenharmony_ci	dist->nr_spis = 0;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
3408c2ecf20Sopenharmony_ci		list_for_each_entry_safe(rdreg, next, &dist->rd_regions, list) {
3418c2ecf20Sopenharmony_ci			list_del(&rdreg->list);
3428c2ecf20Sopenharmony_ci			kfree(rdreg);
3438c2ecf20Sopenharmony_ci		}
3448c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&dist->rd_regions);
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (vgic_has_its(kvm))
3488c2ecf20Sopenharmony_ci		vgic_lpi_translation_cache_destroy(kvm);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (vgic_supports_direct_msis(kvm))
3518c2ecf20Sopenharmony_ci		vgic_v4_teardown(kvm);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_civoid kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/*
3598c2ecf20Sopenharmony_ci	 * Retire all pending LPIs on this vcpu anyway as we're
3608c2ecf20Sopenharmony_ci	 * going to destroy it.
3618c2ecf20Sopenharmony_ci	 */
3628c2ecf20Sopenharmony_ci	vgic_flush_pending_lpis(vcpu);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci/* To be called with kvm->lock held */
3688c2ecf20Sopenharmony_cistatic void __kvm_vgic_destroy(struct kvm *kvm)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu;
3718c2ecf20Sopenharmony_ci	int i;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	vgic_debug_destroy(kvm);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	kvm_for_each_vcpu(i, vcpu, kvm)
3768c2ecf20Sopenharmony_ci		kvm_vgic_vcpu_destroy(vcpu);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	kvm_vgic_dist_destroy(kvm);
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_civoid kvm_vgic_destroy(struct kvm *kvm)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	mutex_lock(&kvm->lock);
3848c2ecf20Sopenharmony_ci	__kvm_vgic_destroy(kvm);
3858c2ecf20Sopenharmony_ci	mutex_unlock(&kvm->lock);
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci/**
3898c2ecf20Sopenharmony_ci * vgic_lazy_init: Lazy init is only allowed if the GIC exposed to the guest
3908c2ecf20Sopenharmony_ci * is a GICv2. A GICv3 must be explicitly initialized by the guest using the
3918c2ecf20Sopenharmony_ci * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group.
3928c2ecf20Sopenharmony_ci * @kvm: kvm struct pointer
3938c2ecf20Sopenharmony_ci */
3948c2ecf20Sopenharmony_ciint vgic_lazy_init(struct kvm *kvm)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	int ret = 0;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (unlikely(!vgic_initialized(kvm))) {
3998c2ecf20Sopenharmony_ci		/*
4008c2ecf20Sopenharmony_ci		 * We only provide the automatic initialization of the VGIC
4018c2ecf20Sopenharmony_ci		 * for the legacy case of a GICv2. Any other type must
4028c2ecf20Sopenharmony_ci		 * be explicitly initialized once setup with the respective
4038c2ecf20Sopenharmony_ci		 * KVM device call.
4048c2ecf20Sopenharmony_ci		 */
4058c2ecf20Sopenharmony_ci		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
4068c2ecf20Sopenharmony_ci			return -EBUSY;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		mutex_lock(&kvm->lock);
4098c2ecf20Sopenharmony_ci		ret = vgic_init(kvm);
4108c2ecf20Sopenharmony_ci		mutex_unlock(&kvm->lock);
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return ret;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci/* RESOURCE MAPPING */
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci/**
4198c2ecf20Sopenharmony_ci * Map the MMIO regions depending on the VGIC model exposed to the guest
4208c2ecf20Sopenharmony_ci * called on the first VCPU run.
4218c2ecf20Sopenharmony_ci * Also map the virtual CPU interface into the VM.
4228c2ecf20Sopenharmony_ci * v2/v3 derivatives call vgic_init if not already done.
4238c2ecf20Sopenharmony_ci * vgic_ready() returns true if this function has succeeded.
4248c2ecf20Sopenharmony_ci * @kvm: kvm struct pointer
4258c2ecf20Sopenharmony_ci */
4268c2ecf20Sopenharmony_ciint kvm_vgic_map_resources(struct kvm *kvm)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
4298c2ecf20Sopenharmony_ci	int ret = 0;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	mutex_lock(&kvm->lock);
4328c2ecf20Sopenharmony_ci	if (!irqchip_in_kernel(kvm))
4338c2ecf20Sopenharmony_ci		goto out;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
4368c2ecf20Sopenharmony_ci		ret = vgic_v2_map_resources(kvm);
4378c2ecf20Sopenharmony_ci	else
4388c2ecf20Sopenharmony_ci		ret = vgic_v3_map_resources(kvm);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if (ret)
4418c2ecf20Sopenharmony_ci		__kvm_vgic_destroy(kvm);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ciout:
4448c2ecf20Sopenharmony_ci	mutex_unlock(&kvm->lock);
4458c2ecf20Sopenharmony_ci	return ret;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci/* GENERIC PROBE */
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic int vgic_init_cpu_starting(unsigned int cpu)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0);
4538c2ecf20Sopenharmony_ci	return 0;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic int vgic_init_cpu_dying(unsigned int cpu)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	disable_percpu_irq(kvm_vgic_global_state.maint_irq);
4608c2ecf20Sopenharmony_ci	return 0;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic irqreturn_t vgic_maintenance_handler(int irq, void *data)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	/*
4668c2ecf20Sopenharmony_ci	 * We cannot rely on the vgic maintenance interrupt to be
4678c2ecf20Sopenharmony_ci	 * delivered synchronously. This means we can only use it to
4688c2ecf20Sopenharmony_ci	 * exit the VM, and we perform the handling of EOIed
4698c2ecf20Sopenharmony_ci	 * interrupts on the exit path (see vgic_fold_lr_state).
4708c2ecf20Sopenharmony_ci	 */
4718c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci/**
4758c2ecf20Sopenharmony_ci * kvm_vgic_init_cpu_hardware - initialize the GIC VE hardware
4768c2ecf20Sopenharmony_ci *
4778c2ecf20Sopenharmony_ci * For a specific CPU, initialize the GIC VE hardware.
4788c2ecf20Sopenharmony_ci */
4798c2ecf20Sopenharmony_civoid kvm_vgic_init_cpu_hardware(void)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	BUG_ON(preemptible());
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/*
4848c2ecf20Sopenharmony_ci	 * We want to make sure the list registers start out clear so that we
4858c2ecf20Sopenharmony_ci	 * only have the program the used registers.
4868c2ecf20Sopenharmony_ci	 */
4878c2ecf20Sopenharmony_ci	if (kvm_vgic_global_state.type == VGIC_V2)
4888c2ecf20Sopenharmony_ci		vgic_v2_init_lrs();
4898c2ecf20Sopenharmony_ci	else
4908c2ecf20Sopenharmony_ci		kvm_call_hyp(__vgic_v3_init_lrs);
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci/**
4948c2ecf20Sopenharmony_ci * kvm_vgic_hyp_init: populates the kvm_vgic_global_state variable
4958c2ecf20Sopenharmony_ci * according to the host GIC model. Accordingly calls either
4968c2ecf20Sopenharmony_ci * vgic_v2/v3_probe which registers the KVM_DEVICE that can be
4978c2ecf20Sopenharmony_ci * instantiated by a guest later on .
4988c2ecf20Sopenharmony_ci */
4998c2ecf20Sopenharmony_ciint kvm_vgic_hyp_init(void)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	const struct gic_kvm_info *gic_kvm_info;
5028c2ecf20Sopenharmony_ci	int ret;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	gic_kvm_info = gic_get_kvm_info();
5058c2ecf20Sopenharmony_ci	if (!gic_kvm_info)
5068c2ecf20Sopenharmony_ci		return -ENODEV;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (!gic_kvm_info->maint_irq) {
5098c2ecf20Sopenharmony_ci		kvm_err("No vgic maintenance irq\n");
5108c2ecf20Sopenharmony_ci		return -ENXIO;
5118c2ecf20Sopenharmony_ci	}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	switch (gic_kvm_info->type) {
5148c2ecf20Sopenharmony_ci	case GIC_V2:
5158c2ecf20Sopenharmony_ci		ret = vgic_v2_probe(gic_kvm_info);
5168c2ecf20Sopenharmony_ci		break;
5178c2ecf20Sopenharmony_ci	case GIC_V3:
5188c2ecf20Sopenharmony_ci		ret = vgic_v3_probe(gic_kvm_info);
5198c2ecf20Sopenharmony_ci		if (!ret) {
5208c2ecf20Sopenharmony_ci			static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif);
5218c2ecf20Sopenharmony_ci			kvm_info("GIC system register CPU interface enabled\n");
5228c2ecf20Sopenharmony_ci		}
5238c2ecf20Sopenharmony_ci		break;
5248c2ecf20Sopenharmony_ci	default:
5258c2ecf20Sopenharmony_ci		ret = -ENODEV;
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (ret)
5298c2ecf20Sopenharmony_ci		return ret;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	kvm_vgic_global_state.maint_irq = gic_kvm_info->maint_irq;
5328c2ecf20Sopenharmony_ci	ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
5338c2ecf20Sopenharmony_ci				 vgic_maintenance_handler,
5348c2ecf20Sopenharmony_ci				 "vgic", kvm_get_running_vcpus());
5358c2ecf20Sopenharmony_ci	if (ret) {
5368c2ecf20Sopenharmony_ci		kvm_err("Cannot register interrupt %d\n",
5378c2ecf20Sopenharmony_ci			kvm_vgic_global_state.maint_irq);
5388c2ecf20Sopenharmony_ci		return ret;
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	ret = cpuhp_setup_state(CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
5428c2ecf20Sopenharmony_ci				"kvm/arm/vgic:starting",
5438c2ecf20Sopenharmony_ci				vgic_init_cpu_starting, vgic_init_cpu_dying);
5448c2ecf20Sopenharmony_ci	if (ret) {
5458c2ecf20Sopenharmony_ci		kvm_err("Cannot register vgic CPU notifier\n");
5468c2ecf20Sopenharmony_ci		goto out_free_irq;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	kvm_info("vgic interrupt IRQ%d\n", kvm_vgic_global_state.maint_irq);
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ciout_free_irq:
5538c2ecf20Sopenharmony_ci	free_percpu_irq(kvm_vgic_global_state.maint_irq,
5548c2ecf20Sopenharmony_ci			kvm_get_running_vcpus());
5558c2ecf20Sopenharmony_ci	return ret;
5568c2ecf20Sopenharmony_ci}
557