18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * GICv3 ITS emulation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015,2016 ARM Ltd.
68c2ecf20Sopenharmony_ci * Author: Andre Przywara <andre.przywara@arm.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/cpu.h>
108c2ecf20Sopenharmony_ci#include <linux/kvm.h>
118c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/list.h>
148c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
158c2ecf20Sopenharmony_ci#include <linux/list_sort.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/irqchip/arm-gic-v3.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h>
208c2ecf20Sopenharmony_ci#include <asm/kvm_arm.h>
218c2ecf20Sopenharmony_ci#include <asm/kvm_mmu.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "vgic.h"
248c2ecf20Sopenharmony_ci#include "vgic-mmio.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic int vgic_its_save_tables_v0(struct vgic_its *its);
278c2ecf20Sopenharmony_cistatic int vgic_its_restore_tables_v0(struct vgic_its *its);
288c2ecf20Sopenharmony_cistatic int vgic_its_commit_v0(struct vgic_its *its);
298c2ecf20Sopenharmony_cistatic int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
308c2ecf20Sopenharmony_ci			     struct kvm_vcpu *filter_vcpu, bool needs_inv);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * Creates a new (reference to a) struct vgic_irq for a given LPI.
348c2ecf20Sopenharmony_ci * If this LPI is already mapped on another ITS, we increase its refcount
358c2ecf20Sopenharmony_ci * and return a pointer to the existing structure.
368c2ecf20Sopenharmony_ci * If this is a "new" LPI, we allocate and initialize a new struct vgic_irq.
378c2ecf20Sopenharmony_ci * This function returns a pointer to the _unlocked_ structure.
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_cistatic struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
408c2ecf20Sopenharmony_ci				     struct kvm_vcpu *vcpu)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
438c2ecf20Sopenharmony_ci	struct vgic_irq *irq = vgic_get_irq(kvm, NULL, intid), *oldirq;
448c2ecf20Sopenharmony_ci	unsigned long flags;
458c2ecf20Sopenharmony_ci	int ret;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* In this case there is no put, since we keep the reference. */
488c2ecf20Sopenharmony_ci	if (irq)
498c2ecf20Sopenharmony_ci		return irq;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	irq = kzalloc(sizeof(struct vgic_irq), GFP_KERNEL);
528c2ecf20Sopenharmony_ci	if (!irq)
538c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&irq->lpi_list);
568c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&irq->ap_list);
578c2ecf20Sopenharmony_ci	raw_spin_lock_init(&irq->irq_lock);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	irq->config = VGIC_CONFIG_EDGE;
608c2ecf20Sopenharmony_ci	kref_init(&irq->refcount);
618c2ecf20Sopenharmony_ci	irq->intid = intid;
628c2ecf20Sopenharmony_ci	irq->target_vcpu = vcpu;
638c2ecf20Sopenharmony_ci	irq->group = 1;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/*
688c2ecf20Sopenharmony_ci	 * There could be a race with another vgic_add_lpi(), so we need to
698c2ecf20Sopenharmony_ci	 * check that we don't add a second list entry with the same LPI.
708c2ecf20Sopenharmony_ci	 */
718c2ecf20Sopenharmony_ci	list_for_each_entry(oldirq, &dist->lpi_list_head, lpi_list) {
728c2ecf20Sopenharmony_ci		if (oldirq->intid != intid)
738c2ecf20Sopenharmony_ci			continue;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		/* Someone was faster with adding this LPI, lets use that. */
768c2ecf20Sopenharmony_ci		kfree(irq);
778c2ecf20Sopenharmony_ci		irq = oldirq;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci		/*
808c2ecf20Sopenharmony_ci		 * This increases the refcount, the caller is expected to
818c2ecf20Sopenharmony_ci		 * call vgic_put_irq() on the returned pointer once it's
828c2ecf20Sopenharmony_ci		 * finished with the IRQ.
838c2ecf20Sopenharmony_ci		 */
848c2ecf20Sopenharmony_ci		vgic_get_irq_kref(irq);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		goto out_unlock;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	list_add_tail(&irq->lpi_list, &dist->lpi_list_head);
908c2ecf20Sopenharmony_ci	dist->lpi_list_count++;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciout_unlock:
938c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/*
968c2ecf20Sopenharmony_ci	 * We "cache" the configuration table entries in our struct vgic_irq's.
978c2ecf20Sopenharmony_ci	 * However we only have those structs for mapped IRQs, so we read in
988c2ecf20Sopenharmony_ci	 * the respective config data from memory here upon mapping the LPI.
998c2ecf20Sopenharmony_ci	 *
1008c2ecf20Sopenharmony_ci	 * Should any of these fail, behave as if we couldn't create the LPI
1018c2ecf20Sopenharmony_ci	 * by dropping the refcount and returning the error.
1028c2ecf20Sopenharmony_ci	 */
1038c2ecf20Sopenharmony_ci	ret = update_lpi_config(kvm, irq, NULL, false);
1048c2ecf20Sopenharmony_ci	if (ret) {
1058c2ecf20Sopenharmony_ci		vgic_put_irq(kvm, irq);
1068c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	ret = vgic_v3_lpi_sync_pending_status(kvm, irq);
1108c2ecf20Sopenharmony_ci	if (ret) {
1118c2ecf20Sopenharmony_ci		vgic_put_irq(kvm, irq);
1128c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	return irq;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistruct its_device {
1198c2ecf20Sopenharmony_ci	struct list_head dev_list;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* the head for the list of ITTEs */
1228c2ecf20Sopenharmony_ci	struct list_head itt_head;
1238c2ecf20Sopenharmony_ci	u32 num_eventid_bits;
1248c2ecf20Sopenharmony_ci	gpa_t itt_addr;
1258c2ecf20Sopenharmony_ci	u32 device_id;
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci#define COLLECTION_NOT_MAPPED ((u32)~0)
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistruct its_collection {
1318c2ecf20Sopenharmony_ci	struct list_head coll_list;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	u32 collection_id;
1348c2ecf20Sopenharmony_ci	u32 target_addr;
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define its_is_collection_mapped(coll) ((coll) && \
1388c2ecf20Sopenharmony_ci				((coll)->target_addr != COLLECTION_NOT_MAPPED))
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistruct its_ite {
1418c2ecf20Sopenharmony_ci	struct list_head ite_list;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	struct vgic_irq *irq;
1448c2ecf20Sopenharmony_ci	struct its_collection *collection;
1458c2ecf20Sopenharmony_ci	u32 event_id;
1468c2ecf20Sopenharmony_ci};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistruct vgic_translation_cache_entry {
1498c2ecf20Sopenharmony_ci	struct list_head	entry;
1508c2ecf20Sopenharmony_ci	phys_addr_t		db;
1518c2ecf20Sopenharmony_ci	u32			devid;
1528c2ecf20Sopenharmony_ci	u32			eventid;
1538c2ecf20Sopenharmony_ci	struct vgic_irq		*irq;
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/**
1578c2ecf20Sopenharmony_ci * struct vgic_its_abi - ITS abi ops and settings
1588c2ecf20Sopenharmony_ci * @cte_esz: collection table entry size
1598c2ecf20Sopenharmony_ci * @dte_esz: device table entry size
1608c2ecf20Sopenharmony_ci * @ite_esz: interrupt translation table entry size
1618c2ecf20Sopenharmony_ci * @save tables: save the ITS tables into guest RAM
1628c2ecf20Sopenharmony_ci * @restore_tables: restore the ITS internal structs from tables
1638c2ecf20Sopenharmony_ci *  stored in guest RAM
1648c2ecf20Sopenharmony_ci * @commit: initialize the registers which expose the ABI settings,
1658c2ecf20Sopenharmony_ci *  especially the entry sizes
1668c2ecf20Sopenharmony_ci */
1678c2ecf20Sopenharmony_cistruct vgic_its_abi {
1688c2ecf20Sopenharmony_ci	int cte_esz;
1698c2ecf20Sopenharmony_ci	int dte_esz;
1708c2ecf20Sopenharmony_ci	int ite_esz;
1718c2ecf20Sopenharmony_ci	int (*save_tables)(struct vgic_its *its);
1728c2ecf20Sopenharmony_ci	int (*restore_tables)(struct vgic_its *its);
1738c2ecf20Sopenharmony_ci	int (*commit)(struct vgic_its *its);
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci#define ABI_0_ESZ	8
1778c2ecf20Sopenharmony_ci#define ESZ_MAX		ABI_0_ESZ
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic const struct vgic_its_abi its_table_abi_versions[] = {
1808c2ecf20Sopenharmony_ci	[0] = {
1818c2ecf20Sopenharmony_ci	 .cte_esz = ABI_0_ESZ,
1828c2ecf20Sopenharmony_ci	 .dte_esz = ABI_0_ESZ,
1838c2ecf20Sopenharmony_ci	 .ite_esz = ABI_0_ESZ,
1848c2ecf20Sopenharmony_ci	 .save_tables = vgic_its_save_tables_v0,
1858c2ecf20Sopenharmony_ci	 .restore_tables = vgic_its_restore_tables_v0,
1868c2ecf20Sopenharmony_ci	 .commit = vgic_its_commit_v0,
1878c2ecf20Sopenharmony_ci	},
1888c2ecf20Sopenharmony_ci};
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci#define NR_ITS_ABIS	ARRAY_SIZE(its_table_abi_versions)
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ciinline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	return &its_table_abi_versions[its->abi_rev];
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int vgic_its_set_abi(struct vgic_its *its, u32 rev)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	its->abi_rev = rev;
2028c2ecf20Sopenharmony_ci	abi = vgic_its_get_abi(its);
2038c2ecf20Sopenharmony_ci	return abi->commit(its);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/*
2078c2ecf20Sopenharmony_ci * Find and returns a device in the device table for an ITS.
2088c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
2098c2ecf20Sopenharmony_ci */
2108c2ecf20Sopenharmony_cistatic struct its_device *find_its_device(struct vgic_its *its, u32 device_id)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct its_device *device;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	list_for_each_entry(device, &its->device_list, dev_list)
2158c2ecf20Sopenharmony_ci		if (device_id == device->device_id)
2168c2ecf20Sopenharmony_ci			return device;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return NULL;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci/*
2228c2ecf20Sopenharmony_ci * Find and returns an interrupt translation table entry (ITTE) for a given
2238c2ecf20Sopenharmony_ci * Device ID/Event ID pair on an ITS.
2248c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
2258c2ecf20Sopenharmony_ci */
2268c2ecf20Sopenharmony_cistatic struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
2278c2ecf20Sopenharmony_ci				  u32 event_id)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct its_device *device;
2308c2ecf20Sopenharmony_ci	struct its_ite *ite;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	device = find_its_device(its, device_id);
2338c2ecf20Sopenharmony_ci	if (device == NULL)
2348c2ecf20Sopenharmony_ci		return NULL;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	list_for_each_entry(ite, &device->itt_head, ite_list)
2378c2ecf20Sopenharmony_ci		if (ite->event_id == event_id)
2388c2ecf20Sopenharmony_ci			return ite;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return NULL;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci/* To be used as an iterator this macro misses the enclosing parentheses */
2448c2ecf20Sopenharmony_ci#define for_each_lpi_its(dev, ite, its) \
2458c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &(its)->device_list, dev_list) \
2468c2ecf20Sopenharmony_ci		list_for_each_entry(ite, &(dev)->itt_head, ite_list)
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci#define GIC_LPI_OFFSET 8192
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci#define VITS_TYPER_IDBITS 16
2518c2ecf20Sopenharmony_ci#define VITS_TYPER_DEVBITS 16
2528c2ecf20Sopenharmony_ci#define VITS_DTE_MAX_DEVID_OFFSET	(BIT(14) - 1)
2538c2ecf20Sopenharmony_ci#define VITS_ITE_MAX_EVENTID_OFFSET	(BIT(16) - 1)
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/*
2568c2ecf20Sopenharmony_ci * Finds and returns a collection in the ITS collection table.
2578c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
2588c2ecf20Sopenharmony_ci */
2598c2ecf20Sopenharmony_cistatic struct its_collection *find_collection(struct vgic_its *its, int coll_id)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	struct its_collection *collection;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	list_for_each_entry(collection, &its->collection_list, coll_list) {
2648c2ecf20Sopenharmony_ci		if (coll_id == collection->collection_id)
2658c2ecf20Sopenharmony_ci			return collection;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	return NULL;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci#define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
2728c2ecf20Sopenharmony_ci#define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/*
2758c2ecf20Sopenharmony_ci * Reads the configuration data for a given LPI from guest memory and
2768c2ecf20Sopenharmony_ci * updates the fields in struct vgic_irq.
2778c2ecf20Sopenharmony_ci * If filter_vcpu is not NULL, applies only if the IRQ is targeting this
2788c2ecf20Sopenharmony_ci * VCPU. Unconditionally applies if filter_vcpu is NULL.
2798c2ecf20Sopenharmony_ci */
2808c2ecf20Sopenharmony_cistatic int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
2818c2ecf20Sopenharmony_ci			     struct kvm_vcpu *filter_vcpu, bool needs_inv)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	u64 propbase = GICR_PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
2848c2ecf20Sopenharmony_ci	u8 prop;
2858c2ecf20Sopenharmony_ci	int ret;
2868c2ecf20Sopenharmony_ci	unsigned long flags;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	ret = kvm_read_guest_lock(kvm, propbase + irq->intid - GIC_LPI_OFFSET,
2898c2ecf20Sopenharmony_ci				  &prop, 1);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (ret)
2928c2ecf20Sopenharmony_ci		return ret;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&irq->irq_lock, flags);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (!filter_vcpu || filter_vcpu == irq->target_vcpu) {
2978c2ecf20Sopenharmony_ci		irq->priority = LPI_PROP_PRIORITY(prop);
2988c2ecf20Sopenharmony_ci		irq->enabled = LPI_PROP_ENABLE_BIT(prop);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		if (!irq->hw) {
3018c2ecf20Sopenharmony_ci			vgic_queue_irq_unlock(kvm, irq, flags);
3028c2ecf20Sopenharmony_ci			return 0;
3038c2ecf20Sopenharmony_ci		}
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (irq->hw)
3098c2ecf20Sopenharmony_ci		return its_prop_update_vlpi(irq->host_irq, prop, needs_inv);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	return 0;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci/*
3158c2ecf20Sopenharmony_ci * Create a snapshot of the current LPIs targeting @vcpu, so that we can
3168c2ecf20Sopenharmony_ci * enumerate those LPIs without holding any lock.
3178c2ecf20Sopenharmony_ci * Returns their number and puts the kmalloc'ed array into intid_ptr.
3188c2ecf20Sopenharmony_ci */
3198c2ecf20Sopenharmony_ciint vgic_copy_lpi_list(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 **intid_ptr)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
3228c2ecf20Sopenharmony_ci	struct vgic_irq *irq;
3238c2ecf20Sopenharmony_ci	unsigned long flags;
3248c2ecf20Sopenharmony_ci	u32 *intids;
3258c2ecf20Sopenharmony_ci	int irq_count, i = 0;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/*
3288c2ecf20Sopenharmony_ci	 * There is an obvious race between allocating the array and LPIs
3298c2ecf20Sopenharmony_ci	 * being mapped/unmapped. If we ended up here as a result of a
3308c2ecf20Sopenharmony_ci	 * command, we're safe (locks are held, preventing another
3318c2ecf20Sopenharmony_ci	 * command). If coming from another path (such as enabling LPIs),
3328c2ecf20Sopenharmony_ci	 * we must be careful not to overrun the array.
3338c2ecf20Sopenharmony_ci	 */
3348c2ecf20Sopenharmony_ci	irq_count = READ_ONCE(dist->lpi_list_count);
3358c2ecf20Sopenharmony_ci	intids = kmalloc_array(irq_count, sizeof(intids[0]), GFP_KERNEL);
3368c2ecf20Sopenharmony_ci	if (!intids)
3378c2ecf20Sopenharmony_ci		return -ENOMEM;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
3408c2ecf20Sopenharmony_ci	list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
3418c2ecf20Sopenharmony_ci		if (i == irq_count)
3428c2ecf20Sopenharmony_ci			break;
3438c2ecf20Sopenharmony_ci		/* We don't need to "get" the IRQ, as we hold the list lock. */
3448c2ecf20Sopenharmony_ci		if (vcpu && irq->target_vcpu != vcpu)
3458c2ecf20Sopenharmony_ci			continue;
3468c2ecf20Sopenharmony_ci		intids[i++] = irq->intid;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	*intid_ptr = intids;
3518c2ecf20Sopenharmony_ci	return i;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic int update_affinity(struct vgic_irq *irq, struct kvm_vcpu *vcpu)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	int ret = 0;
3578c2ecf20Sopenharmony_ci	unsigned long flags;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&irq->irq_lock, flags);
3608c2ecf20Sopenharmony_ci	irq->target_vcpu = vcpu;
3618c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (irq->hw) {
3648c2ecf20Sopenharmony_ci		struct its_vlpi_map map;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci		ret = its_get_vlpi(irq->host_irq, &map);
3678c2ecf20Sopenharmony_ci		if (ret)
3688c2ecf20Sopenharmony_ci			return ret;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		if (map.vpe)
3718c2ecf20Sopenharmony_ci			atomic_dec(&map.vpe->vlpi_count);
3728c2ecf20Sopenharmony_ci		map.vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
3738c2ecf20Sopenharmony_ci		atomic_inc(&map.vpe->vlpi_count);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci		ret = its_map_vlpi(irq->host_irq, &map);
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	return ret;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci/*
3828c2ecf20Sopenharmony_ci * Promotes the ITS view of affinity of an ITTE (which redistributor this LPI
3838c2ecf20Sopenharmony_ci * is targeting) to the VGIC's view, which deals with target VCPUs.
3848c2ecf20Sopenharmony_ci * Needs to be called whenever either the collection for a LPIs has
3858c2ecf20Sopenharmony_ci * changed or the collection itself got retargeted.
3868c2ecf20Sopenharmony_ci */
3878c2ecf20Sopenharmony_cistatic void update_affinity_ite(struct kvm *kvm, struct its_ite *ite)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	if (!its_is_collection_mapped(ite->collection))
3928c2ecf20Sopenharmony_ci		return;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	vcpu = kvm_get_vcpu(kvm, ite->collection->target_addr);
3958c2ecf20Sopenharmony_ci	update_affinity(ite->irq, vcpu);
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci/*
3998c2ecf20Sopenharmony_ci * Updates the target VCPU for every LPI targeting this collection.
4008c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
4018c2ecf20Sopenharmony_ci */
4028c2ecf20Sopenharmony_cistatic void update_affinity_collection(struct kvm *kvm, struct vgic_its *its,
4038c2ecf20Sopenharmony_ci				       struct its_collection *coll)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	struct its_device *device;
4068c2ecf20Sopenharmony_ci	struct its_ite *ite;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	for_each_lpi_its(device, ite, its) {
4098c2ecf20Sopenharmony_ci		if (!ite->collection || coll != ite->collection)
4108c2ecf20Sopenharmony_ci			continue;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		update_affinity_ite(kvm, ite);
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic u32 max_lpis_propbaser(u64 propbaser)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	int nr_idbits = (propbaser & 0x1f) + 1;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	return 1U << min(nr_idbits, INTERRUPT_ID_BITS_ITS);
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci/*
4248c2ecf20Sopenharmony_ci * Sync the pending table pending bit of LPIs targeting @vcpu
4258c2ecf20Sopenharmony_ci * with our own data structures. This relies on the LPI being
4268c2ecf20Sopenharmony_ci * mapped before.
4278c2ecf20Sopenharmony_ci */
4288c2ecf20Sopenharmony_cistatic int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	gpa_t pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
4318c2ecf20Sopenharmony_ci	struct vgic_irq *irq;
4328c2ecf20Sopenharmony_ci	int last_byte_offset = -1;
4338c2ecf20Sopenharmony_ci	int ret = 0;
4348c2ecf20Sopenharmony_ci	u32 *intids;
4358c2ecf20Sopenharmony_ci	int nr_irqs, i;
4368c2ecf20Sopenharmony_ci	unsigned long flags;
4378c2ecf20Sopenharmony_ci	u8 pendmask;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	nr_irqs = vgic_copy_lpi_list(vcpu->kvm, vcpu, &intids);
4408c2ecf20Sopenharmony_ci	if (nr_irqs < 0)
4418c2ecf20Sopenharmony_ci		return nr_irqs;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	for (i = 0; i < nr_irqs; i++) {
4448c2ecf20Sopenharmony_ci		int byte_offset, bit_nr;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		byte_offset = intids[i] / BITS_PER_BYTE;
4478c2ecf20Sopenharmony_ci		bit_nr = intids[i] % BITS_PER_BYTE;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci		/*
4508c2ecf20Sopenharmony_ci		 * For contiguously allocated LPIs chances are we just read
4518c2ecf20Sopenharmony_ci		 * this very same byte in the last iteration. Reuse that.
4528c2ecf20Sopenharmony_ci		 */
4538c2ecf20Sopenharmony_ci		if (byte_offset != last_byte_offset) {
4548c2ecf20Sopenharmony_ci			ret = kvm_read_guest_lock(vcpu->kvm,
4558c2ecf20Sopenharmony_ci						  pendbase + byte_offset,
4568c2ecf20Sopenharmony_ci						  &pendmask, 1);
4578c2ecf20Sopenharmony_ci			if (ret) {
4588c2ecf20Sopenharmony_ci				kfree(intids);
4598c2ecf20Sopenharmony_ci				return ret;
4608c2ecf20Sopenharmony_ci			}
4618c2ecf20Sopenharmony_ci			last_byte_offset = byte_offset;
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		irq = vgic_get_irq(vcpu->kvm, NULL, intids[i]);
4658c2ecf20Sopenharmony_ci		raw_spin_lock_irqsave(&irq->irq_lock, flags);
4668c2ecf20Sopenharmony_ci		irq->pending_latch = pendmask & (1U << bit_nr);
4678c2ecf20Sopenharmony_ci		vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
4688c2ecf20Sopenharmony_ci		vgic_put_irq(vcpu->kvm, irq);
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	kfree(intids);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	return ret;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
4778c2ecf20Sopenharmony_ci					      struct vgic_its *its,
4788c2ecf20Sopenharmony_ci					      gpa_t addr, unsigned int len)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
4818c2ecf20Sopenharmony_ci	u64 reg = GITS_TYPER_PLPIS;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/*
4848c2ecf20Sopenharmony_ci	 * We use linear CPU numbers for redistributor addressing,
4858c2ecf20Sopenharmony_ci	 * so GITS_TYPER.PTA is 0.
4868c2ecf20Sopenharmony_ci	 * Also we force all PROPBASER registers to be the same, so
4878c2ecf20Sopenharmony_ci	 * CommonLPIAff is 0 as well.
4888c2ecf20Sopenharmony_ci	 * To avoid memory waste in the guest, we keep the number of IDBits and
4898c2ecf20Sopenharmony_ci	 * DevBits low - as least for the time being.
4908c2ecf20Sopenharmony_ci	 */
4918c2ecf20Sopenharmony_ci	reg |= GIC_ENCODE_SZ(VITS_TYPER_DEVBITS, 5) << GITS_TYPER_DEVBITS_SHIFT;
4928c2ecf20Sopenharmony_ci	reg |= GIC_ENCODE_SZ(VITS_TYPER_IDBITS, 5) << GITS_TYPER_IDBITS_SHIFT;
4938c2ecf20Sopenharmony_ci	reg |= GIC_ENCODE_SZ(abi->ite_esz, 4) << GITS_TYPER_ITT_ENTRY_SIZE_SHIFT;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return extract_bytes(reg, addr & 7, len);
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic unsigned long vgic_mmio_read_its_iidr(struct kvm *kvm,
4998c2ecf20Sopenharmony_ci					     struct vgic_its *its,
5008c2ecf20Sopenharmony_ci					     gpa_t addr, unsigned int len)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	u32 val;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	val = (its->abi_rev << GITS_IIDR_REV_SHIFT) & GITS_IIDR_REV_MASK;
5058c2ecf20Sopenharmony_ci	val |= (PRODUCT_ID_KVM << GITS_IIDR_PRODUCTID_SHIFT) | IMPLEMENTER_ARM;
5068c2ecf20Sopenharmony_ci	return val;
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int vgic_mmio_uaccess_write_its_iidr(struct kvm *kvm,
5108c2ecf20Sopenharmony_ci					    struct vgic_its *its,
5118c2ecf20Sopenharmony_ci					    gpa_t addr, unsigned int len,
5128c2ecf20Sopenharmony_ci					    unsigned long val)
5138c2ecf20Sopenharmony_ci{
5148c2ecf20Sopenharmony_ci	u32 rev = GITS_IIDR_REV(val);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	if (rev >= NR_ITS_ABIS)
5178c2ecf20Sopenharmony_ci		return -EINVAL;
5188c2ecf20Sopenharmony_ci	return vgic_its_set_abi(its, rev);
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic unsigned long vgic_mmio_read_its_idregs(struct kvm *kvm,
5228c2ecf20Sopenharmony_ci					       struct vgic_its *its,
5238c2ecf20Sopenharmony_ci					       gpa_t addr, unsigned int len)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	switch (addr & 0xffff) {
5268c2ecf20Sopenharmony_ci	case GITS_PIDR0:
5278c2ecf20Sopenharmony_ci		return 0x92;	/* part number, bits[7:0] */
5288c2ecf20Sopenharmony_ci	case GITS_PIDR1:
5298c2ecf20Sopenharmony_ci		return 0xb4;	/* part number, bits[11:8] */
5308c2ecf20Sopenharmony_ci	case GITS_PIDR2:
5318c2ecf20Sopenharmony_ci		return GIC_PIDR2_ARCH_GICv3 | 0x0b;
5328c2ecf20Sopenharmony_ci	case GITS_PIDR4:
5338c2ecf20Sopenharmony_ci		return 0x40;	/* This is a 64K software visible page */
5348c2ecf20Sopenharmony_ci	/* The following are the ID registers for (any) GIC. */
5358c2ecf20Sopenharmony_ci	case GITS_CIDR0:
5368c2ecf20Sopenharmony_ci		return 0x0d;
5378c2ecf20Sopenharmony_ci	case GITS_CIDR1:
5388c2ecf20Sopenharmony_ci		return 0xf0;
5398c2ecf20Sopenharmony_ci	case GITS_CIDR2:
5408c2ecf20Sopenharmony_ci		return 0x05;
5418c2ecf20Sopenharmony_ci	case GITS_CIDR3:
5428c2ecf20Sopenharmony_ci		return 0xb1;
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	return 0;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic struct vgic_irq *__vgic_its_check_cache(struct vgic_dist *dist,
5498c2ecf20Sopenharmony_ci					       phys_addr_t db,
5508c2ecf20Sopenharmony_ci					       u32 devid, u32 eventid)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	struct vgic_translation_cache_entry *cte;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	list_for_each_entry(cte, &dist->lpi_translation_cache, entry) {
5558c2ecf20Sopenharmony_ci		/*
5568c2ecf20Sopenharmony_ci		 * If we hit a NULL entry, there is nothing after this
5578c2ecf20Sopenharmony_ci		 * point.
5588c2ecf20Sopenharmony_ci		 */
5598c2ecf20Sopenharmony_ci		if (!cte->irq)
5608c2ecf20Sopenharmony_ci			break;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci		if (cte->db != db || cte->devid != devid ||
5638c2ecf20Sopenharmony_ci		    cte->eventid != eventid)
5648c2ecf20Sopenharmony_ci			continue;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci		/*
5678c2ecf20Sopenharmony_ci		 * Move this entry to the head, as it is the most
5688c2ecf20Sopenharmony_ci		 * recently used.
5698c2ecf20Sopenharmony_ci		 */
5708c2ecf20Sopenharmony_ci		if (!list_is_first(&cte->entry, &dist->lpi_translation_cache))
5718c2ecf20Sopenharmony_ci			list_move(&cte->entry, &dist->lpi_translation_cache);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci		return cte->irq;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	return NULL;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db,
5808c2ecf20Sopenharmony_ci					     u32 devid, u32 eventid)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
5838c2ecf20Sopenharmony_ci	struct vgic_irq *irq;
5848c2ecf20Sopenharmony_ci	unsigned long flags;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	irq = __vgic_its_check_cache(dist, db, devid, eventid);
5898c2ecf20Sopenharmony_ci	if (irq)
5908c2ecf20Sopenharmony_ci		vgic_get_irq_kref(irq);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	return irq;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its,
5988c2ecf20Sopenharmony_ci				       u32 devid, u32 eventid,
5998c2ecf20Sopenharmony_ci				       struct vgic_irq *irq)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
6028c2ecf20Sopenharmony_ci	struct vgic_translation_cache_entry *cte;
6038c2ecf20Sopenharmony_ci	unsigned long flags;
6048c2ecf20Sopenharmony_ci	phys_addr_t db;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* Do not cache a directly injected interrupt */
6078c2ecf20Sopenharmony_ci	if (irq->hw)
6088c2ecf20Sopenharmony_ci		return;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (unlikely(list_empty(&dist->lpi_translation_cache)))
6138c2ecf20Sopenharmony_ci		goto out;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	/*
6168c2ecf20Sopenharmony_ci	 * We could have raced with another CPU caching the same
6178c2ecf20Sopenharmony_ci	 * translation behind our back, so let's check it is not in
6188c2ecf20Sopenharmony_ci	 * already
6198c2ecf20Sopenharmony_ci	 */
6208c2ecf20Sopenharmony_ci	db = its->vgic_its_base + GITS_TRANSLATER;
6218c2ecf20Sopenharmony_ci	if (__vgic_its_check_cache(dist, db, devid, eventid))
6228c2ecf20Sopenharmony_ci		goto out;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	/* Always reuse the last entry (LRU policy) */
6258c2ecf20Sopenharmony_ci	cte = list_last_entry(&dist->lpi_translation_cache,
6268c2ecf20Sopenharmony_ci			      typeof(*cte), entry);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	/*
6298c2ecf20Sopenharmony_ci	 * Caching the translation implies having an extra reference
6308c2ecf20Sopenharmony_ci	 * to the interrupt, so drop the potential reference on what
6318c2ecf20Sopenharmony_ci	 * was in the cache, and increment it on the new interrupt.
6328c2ecf20Sopenharmony_ci	 */
6338c2ecf20Sopenharmony_ci	if (cte->irq)
6348c2ecf20Sopenharmony_ci		__vgic_put_lpi_locked(kvm, cte->irq);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	vgic_get_irq_kref(irq);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	cte->db		= db;
6398c2ecf20Sopenharmony_ci	cte->devid	= devid;
6408c2ecf20Sopenharmony_ci	cte->eventid	= eventid;
6418c2ecf20Sopenharmony_ci	cte->irq	= irq;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/* Move the new translation to the head of the list */
6448c2ecf20Sopenharmony_ci	list_move(&cte->entry, &dist->lpi_translation_cache);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ciout:
6478c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_civoid vgic_its_invalidate_cache(struct kvm *kvm)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
6538c2ecf20Sopenharmony_ci	struct vgic_translation_cache_entry *cte;
6548c2ecf20Sopenharmony_ci	unsigned long flags;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	list_for_each_entry(cte, &dist->lpi_translation_cache, entry) {
6598c2ecf20Sopenharmony_ci		/*
6608c2ecf20Sopenharmony_ci		 * If we hit a NULL entry, there is nothing after this
6618c2ecf20Sopenharmony_ci		 * point.
6628c2ecf20Sopenharmony_ci		 */
6638c2ecf20Sopenharmony_ci		if (!cte->irq)
6648c2ecf20Sopenharmony_ci			break;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci		__vgic_put_lpi_locked(kvm, cte->irq);
6678c2ecf20Sopenharmony_ci		cte->irq = NULL;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ciint vgic_its_resolve_lpi(struct kvm *kvm, struct vgic_its *its,
6748c2ecf20Sopenharmony_ci			 u32 devid, u32 eventid, struct vgic_irq **irq)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu;
6778c2ecf20Sopenharmony_ci	struct its_ite *ite;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	if (!its->enabled)
6808c2ecf20Sopenharmony_ci		return -EBUSY;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	ite = find_ite(its, devid, eventid);
6838c2ecf20Sopenharmony_ci	if (!ite || !its_is_collection_mapped(ite->collection))
6848c2ecf20Sopenharmony_ci		return E_ITS_INT_UNMAPPED_INTERRUPT;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	vcpu = kvm_get_vcpu(kvm, ite->collection->target_addr);
6878c2ecf20Sopenharmony_ci	if (!vcpu)
6888c2ecf20Sopenharmony_ci		return E_ITS_INT_UNMAPPED_INTERRUPT;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (!vcpu->arch.vgic_cpu.lpis_enabled)
6918c2ecf20Sopenharmony_ci		return -EBUSY;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	vgic_its_cache_translation(kvm, its, devid, eventid, ite->irq);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	*irq = ite->irq;
6968c2ecf20Sopenharmony_ci	return 0;
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cistruct vgic_its *vgic_msi_to_its(struct kvm *kvm, struct kvm_msi *msi)
7008c2ecf20Sopenharmony_ci{
7018c2ecf20Sopenharmony_ci	u64 address;
7028c2ecf20Sopenharmony_ci	struct kvm_io_device *kvm_io_dev;
7038c2ecf20Sopenharmony_ci	struct vgic_io_device *iodev;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	if (!vgic_has_its(kvm))
7068c2ecf20Sopenharmony_ci		return ERR_PTR(-ENODEV);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (!(msi->flags & KVM_MSI_VALID_DEVID))
7098c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	address = (u64)msi->address_hi << 32 | msi->address_lo;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	kvm_io_dev = kvm_io_bus_get_dev(kvm, KVM_MMIO_BUS, address);
7148c2ecf20Sopenharmony_ci	if (!kvm_io_dev)
7158c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (kvm_io_dev->ops != &kvm_io_gic_ops)
7188c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	iodev = container_of(kvm_io_dev, struct vgic_io_device, dev);
7218c2ecf20Sopenharmony_ci	if (iodev->iodev_type != IODEV_ITS)
7228c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	return iodev->its;
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci/*
7288c2ecf20Sopenharmony_ci * Find the target VCPU and the LPI number for a given devid/eventid pair
7298c2ecf20Sopenharmony_ci * and make this IRQ pending, possibly injecting it.
7308c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
7318c2ecf20Sopenharmony_ci * Returns 0 on success, a positive error value for any ITS mapping
7328c2ecf20Sopenharmony_ci * related errors and negative error values for generic errors.
7338c2ecf20Sopenharmony_ci */
7348c2ecf20Sopenharmony_cistatic int vgic_its_trigger_msi(struct kvm *kvm, struct vgic_its *its,
7358c2ecf20Sopenharmony_ci				u32 devid, u32 eventid)
7368c2ecf20Sopenharmony_ci{
7378c2ecf20Sopenharmony_ci	struct vgic_irq *irq = NULL;
7388c2ecf20Sopenharmony_ci	unsigned long flags;
7398c2ecf20Sopenharmony_ci	int err;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	err = vgic_its_resolve_lpi(kvm, its, devid, eventid, &irq);
7428c2ecf20Sopenharmony_ci	if (err)
7438c2ecf20Sopenharmony_ci		return err;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	if (irq->hw)
7468c2ecf20Sopenharmony_ci		return irq_set_irqchip_state(irq->host_irq,
7478c2ecf20Sopenharmony_ci					     IRQCHIP_STATE_PENDING, true);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&irq->irq_lock, flags);
7508c2ecf20Sopenharmony_ci	irq->pending_latch = true;
7518c2ecf20Sopenharmony_ci	vgic_queue_irq_unlock(kvm, irq, flags);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	return 0;
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ciint vgic_its_inject_cached_translation(struct kvm *kvm, struct kvm_msi *msi)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct vgic_irq *irq;
7598c2ecf20Sopenharmony_ci	unsigned long flags;
7608c2ecf20Sopenharmony_ci	phys_addr_t db;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	db = (u64)msi->address_hi << 32 | msi->address_lo;
7638c2ecf20Sopenharmony_ci	irq = vgic_its_check_cache(kvm, db, msi->devid, msi->data);
7648c2ecf20Sopenharmony_ci	if (!irq)
7658c2ecf20Sopenharmony_ci		return -EWOULDBLOCK;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&irq->irq_lock, flags);
7688c2ecf20Sopenharmony_ci	irq->pending_latch = true;
7698c2ecf20Sopenharmony_ci	vgic_queue_irq_unlock(kvm, irq, flags);
7708c2ecf20Sopenharmony_ci	vgic_put_irq(kvm, irq);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	return 0;
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci/*
7768c2ecf20Sopenharmony_ci * Queries the KVM IO bus framework to get the ITS pointer from the given
7778c2ecf20Sopenharmony_ci * doorbell address.
7788c2ecf20Sopenharmony_ci * We then call vgic_its_trigger_msi() with the decoded data.
7798c2ecf20Sopenharmony_ci * According to the KVM_SIGNAL_MSI API description returns 1 on success.
7808c2ecf20Sopenharmony_ci */
7818c2ecf20Sopenharmony_ciint vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct vgic_its *its;
7848c2ecf20Sopenharmony_ci	int ret;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (!vgic_its_inject_cached_translation(kvm, msi))
7878c2ecf20Sopenharmony_ci		return 1;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	its = vgic_msi_to_its(kvm, msi);
7908c2ecf20Sopenharmony_ci	if (IS_ERR(its))
7918c2ecf20Sopenharmony_ci		return PTR_ERR(its);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	mutex_lock(&its->its_lock);
7948c2ecf20Sopenharmony_ci	ret = vgic_its_trigger_msi(kvm, its, msi->devid, msi->data);
7958c2ecf20Sopenharmony_ci	mutex_unlock(&its->its_lock);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	if (ret < 0)
7988c2ecf20Sopenharmony_ci		return ret;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	/*
8018c2ecf20Sopenharmony_ci	 * KVM_SIGNAL_MSI demands a return value > 0 for success and 0
8028c2ecf20Sopenharmony_ci	 * if the guest has blocked the MSI. So we map any LPI mapping
8038c2ecf20Sopenharmony_ci	 * related error to that.
8048c2ecf20Sopenharmony_ci	 */
8058c2ecf20Sopenharmony_ci	if (ret)
8068c2ecf20Sopenharmony_ci		return 0;
8078c2ecf20Sopenharmony_ci	else
8088c2ecf20Sopenharmony_ci		return 1;
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci/* Requires the its_lock to be held. */
8128c2ecf20Sopenharmony_cistatic void its_free_ite(struct kvm *kvm, struct its_ite *ite)
8138c2ecf20Sopenharmony_ci{
8148c2ecf20Sopenharmony_ci	list_del(&ite->ite_list);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	/* This put matches the get in vgic_add_lpi. */
8178c2ecf20Sopenharmony_ci	if (ite->irq) {
8188c2ecf20Sopenharmony_ci		if (ite->irq->hw)
8198c2ecf20Sopenharmony_ci			WARN_ON(its_unmap_vlpi(ite->irq->host_irq));
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		vgic_put_irq(kvm, ite->irq);
8228c2ecf20Sopenharmony_ci	}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	kfree(ite);
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	return (le64_to_cpu(its_cmd[word]) >> shift) & (BIT_ULL(size) - 1);
8308c2ecf20Sopenharmony_ci}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci#define its_cmd_get_command(cmd)	its_cmd_mask_field(cmd, 0,  0,  8)
8338c2ecf20Sopenharmony_ci#define its_cmd_get_deviceid(cmd)	its_cmd_mask_field(cmd, 0, 32, 32)
8348c2ecf20Sopenharmony_ci#define its_cmd_get_size(cmd)		(its_cmd_mask_field(cmd, 1,  0,  5) + 1)
8358c2ecf20Sopenharmony_ci#define its_cmd_get_id(cmd)		its_cmd_mask_field(cmd, 1,  0, 32)
8368c2ecf20Sopenharmony_ci#define its_cmd_get_physical_id(cmd)	its_cmd_mask_field(cmd, 1, 32, 32)
8378c2ecf20Sopenharmony_ci#define its_cmd_get_collection(cmd)	its_cmd_mask_field(cmd, 2,  0, 16)
8388c2ecf20Sopenharmony_ci#define its_cmd_get_ittaddr(cmd)	(its_cmd_mask_field(cmd, 2,  8, 44) << 8)
8398c2ecf20Sopenharmony_ci#define its_cmd_get_target_addr(cmd)	its_cmd_mask_field(cmd, 2, 16, 32)
8408c2ecf20Sopenharmony_ci#define its_cmd_get_validbit(cmd)	its_cmd_mask_field(cmd, 2, 63,  1)
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci/*
8438c2ecf20Sopenharmony_ci * The DISCARD command frees an Interrupt Translation Table Entry (ITTE).
8448c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
8458c2ecf20Sopenharmony_ci */
8468c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its,
8478c2ecf20Sopenharmony_ci				       u64 *its_cmd)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
8508c2ecf20Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
8518c2ecf20Sopenharmony_ci	struct its_ite *ite;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	ite = find_ite(its, device_id, event_id);
8548c2ecf20Sopenharmony_ci	if (ite && its_is_collection_mapped(ite->collection)) {
8558c2ecf20Sopenharmony_ci		/*
8568c2ecf20Sopenharmony_ci		 * Though the spec talks about removing the pending state, we
8578c2ecf20Sopenharmony_ci		 * don't bother here since we clear the ITTE anyway and the
8588c2ecf20Sopenharmony_ci		 * pending state is a property of the ITTE struct.
8598c2ecf20Sopenharmony_ci		 */
8608c2ecf20Sopenharmony_ci		vgic_its_invalidate_cache(kvm);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci		its_free_ite(kvm, ite);
8638c2ecf20Sopenharmony_ci		return 0;
8648c2ecf20Sopenharmony_ci	}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
8678c2ecf20Sopenharmony_ci}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci/*
8708c2ecf20Sopenharmony_ci * The MOVI command moves an ITTE to a different collection.
8718c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
8728c2ecf20Sopenharmony_ci */
8738c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
8748c2ecf20Sopenharmony_ci				    u64 *its_cmd)
8758c2ecf20Sopenharmony_ci{
8768c2ecf20Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
8778c2ecf20Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
8788c2ecf20Sopenharmony_ci	u32 coll_id = its_cmd_get_collection(its_cmd);
8798c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu;
8808c2ecf20Sopenharmony_ci	struct its_ite *ite;
8818c2ecf20Sopenharmony_ci	struct its_collection *collection;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	ite = find_ite(its, device_id, event_id);
8848c2ecf20Sopenharmony_ci	if (!ite)
8858c2ecf20Sopenharmony_ci		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (!its_is_collection_mapped(ite->collection))
8888c2ecf20Sopenharmony_ci		return E_ITS_MOVI_UNMAPPED_COLLECTION;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	collection = find_collection(its, coll_id);
8918c2ecf20Sopenharmony_ci	if (!its_is_collection_mapped(collection))
8928c2ecf20Sopenharmony_ci		return E_ITS_MOVI_UNMAPPED_COLLECTION;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	ite->collection = collection;
8958c2ecf20Sopenharmony_ci	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	vgic_its_invalidate_cache(kvm);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	return update_affinity(ite->irq, vcpu);
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci/*
9038c2ecf20Sopenharmony_ci * Check whether an ID can be stored into the corresponding guest table.
9048c2ecf20Sopenharmony_ci * For a direct table this is pretty easy, but gets a bit nasty for
9058c2ecf20Sopenharmony_ci * indirect tables. We check whether the resulting guest physical address
9068c2ecf20Sopenharmony_ci * is actually valid (covered by a memslot and guest accessible).
9078c2ecf20Sopenharmony_ci * For this we have to read the respective first level entry.
9088c2ecf20Sopenharmony_ci */
9098c2ecf20Sopenharmony_cistatic bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id,
9108c2ecf20Sopenharmony_ci			      gpa_t *eaddr)
9118c2ecf20Sopenharmony_ci{
9128c2ecf20Sopenharmony_ci	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
9138c2ecf20Sopenharmony_ci	u64 indirect_ptr, type = GITS_BASER_TYPE(baser);
9148c2ecf20Sopenharmony_ci	phys_addr_t base = GITS_BASER_ADDR_48_to_52(baser);
9158c2ecf20Sopenharmony_ci	int esz = GITS_BASER_ENTRY_SIZE(baser);
9168c2ecf20Sopenharmony_ci	int index, idx;
9178c2ecf20Sopenharmony_ci	gfn_t gfn;
9188c2ecf20Sopenharmony_ci	bool ret;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	switch (type) {
9218c2ecf20Sopenharmony_ci	case GITS_BASER_TYPE_DEVICE:
9228c2ecf20Sopenharmony_ci		if (id >= BIT_ULL(VITS_TYPER_DEVBITS))
9238c2ecf20Sopenharmony_ci			return false;
9248c2ecf20Sopenharmony_ci		break;
9258c2ecf20Sopenharmony_ci	case GITS_BASER_TYPE_COLLECTION:
9268c2ecf20Sopenharmony_ci		/* as GITS_TYPER.CIL == 0, ITS supports 16-bit collection ID */
9278c2ecf20Sopenharmony_ci		if (id >= BIT_ULL(16))
9288c2ecf20Sopenharmony_ci			return false;
9298c2ecf20Sopenharmony_ci		break;
9308c2ecf20Sopenharmony_ci	default:
9318c2ecf20Sopenharmony_ci		return false;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	if (!(baser & GITS_BASER_INDIRECT)) {
9358c2ecf20Sopenharmony_ci		phys_addr_t addr;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci		if (id >= (l1_tbl_size / esz))
9388c2ecf20Sopenharmony_ci			return false;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci		addr = base + id * esz;
9418c2ecf20Sopenharmony_ci		gfn = addr >> PAGE_SHIFT;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci		if (eaddr)
9448c2ecf20Sopenharmony_ci			*eaddr = addr;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci		goto out;
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	/* calculate and check the index into the 1st level */
9508c2ecf20Sopenharmony_ci	index = id / (SZ_64K / esz);
9518c2ecf20Sopenharmony_ci	if (index >= (l1_tbl_size / sizeof(u64)))
9528c2ecf20Sopenharmony_ci		return false;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	/* Each 1st level entry is represented by a 64-bit value. */
9558c2ecf20Sopenharmony_ci	if (kvm_read_guest_lock(its->dev->kvm,
9568c2ecf20Sopenharmony_ci			   base + index * sizeof(indirect_ptr),
9578c2ecf20Sopenharmony_ci			   &indirect_ptr, sizeof(indirect_ptr)))
9588c2ecf20Sopenharmony_ci		return false;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	indirect_ptr = le64_to_cpu(indirect_ptr);
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	/* check the valid bit of the first level entry */
9638c2ecf20Sopenharmony_ci	if (!(indirect_ptr & BIT_ULL(63)))
9648c2ecf20Sopenharmony_ci		return false;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	/* Mask the guest physical address and calculate the frame number. */
9678c2ecf20Sopenharmony_ci	indirect_ptr &= GENMASK_ULL(51, 16);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	/* Find the address of the actual entry */
9708c2ecf20Sopenharmony_ci	index = id % (SZ_64K / esz);
9718c2ecf20Sopenharmony_ci	indirect_ptr += index * esz;
9728c2ecf20Sopenharmony_ci	gfn = indirect_ptr >> PAGE_SHIFT;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	if (eaddr)
9758c2ecf20Sopenharmony_ci		*eaddr = indirect_ptr;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ciout:
9788c2ecf20Sopenharmony_ci	idx = srcu_read_lock(&its->dev->kvm->srcu);
9798c2ecf20Sopenharmony_ci	ret = kvm_is_visible_gfn(its->dev->kvm, gfn);
9808c2ecf20Sopenharmony_ci	srcu_read_unlock(&its->dev->kvm->srcu, idx);
9818c2ecf20Sopenharmony_ci	return ret;
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_cistatic int vgic_its_alloc_collection(struct vgic_its *its,
9858c2ecf20Sopenharmony_ci				     struct its_collection **colp,
9868c2ecf20Sopenharmony_ci				     u32 coll_id)
9878c2ecf20Sopenharmony_ci{
9888c2ecf20Sopenharmony_ci	struct its_collection *collection;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	if (!vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL))
9918c2ecf20Sopenharmony_ci		return E_ITS_MAPC_COLLECTION_OOR;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	collection = kzalloc(sizeof(*collection), GFP_KERNEL);
9948c2ecf20Sopenharmony_ci	if (!collection)
9958c2ecf20Sopenharmony_ci		return -ENOMEM;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	collection->collection_id = coll_id;
9988c2ecf20Sopenharmony_ci	collection->target_addr = COLLECTION_NOT_MAPPED;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	list_add_tail(&collection->coll_list, &its->collection_list);
10018c2ecf20Sopenharmony_ci	*colp = collection;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	return 0;
10048c2ecf20Sopenharmony_ci}
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_cistatic void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	struct its_collection *collection;
10098c2ecf20Sopenharmony_ci	struct its_device *device;
10108c2ecf20Sopenharmony_ci	struct its_ite *ite;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	/*
10138c2ecf20Sopenharmony_ci	 * Clearing the mapping for that collection ID removes the
10148c2ecf20Sopenharmony_ci	 * entry from the list. If there wasn't any before, we can
10158c2ecf20Sopenharmony_ci	 * go home early.
10168c2ecf20Sopenharmony_ci	 */
10178c2ecf20Sopenharmony_ci	collection = find_collection(its, coll_id);
10188c2ecf20Sopenharmony_ci	if (!collection)
10198c2ecf20Sopenharmony_ci		return;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	for_each_lpi_its(device, ite, its)
10228c2ecf20Sopenharmony_ci		if (ite->collection &&
10238c2ecf20Sopenharmony_ci		    ite->collection->collection_id == coll_id)
10248c2ecf20Sopenharmony_ci			ite->collection = NULL;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	list_del(&collection->coll_list);
10278c2ecf20Sopenharmony_ci	kfree(collection);
10288c2ecf20Sopenharmony_ci}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci/* Must be called with its_lock mutex held */
10318c2ecf20Sopenharmony_cistatic struct its_ite *vgic_its_alloc_ite(struct its_device *device,
10328c2ecf20Sopenharmony_ci					  struct its_collection *collection,
10338c2ecf20Sopenharmony_ci					  u32 event_id)
10348c2ecf20Sopenharmony_ci{
10358c2ecf20Sopenharmony_ci	struct its_ite *ite;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	ite = kzalloc(sizeof(*ite), GFP_KERNEL);
10388c2ecf20Sopenharmony_ci	if (!ite)
10398c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	ite->event_id	= event_id;
10428c2ecf20Sopenharmony_ci	ite->collection = collection;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	list_add_tail(&ite->ite_list, &device->itt_head);
10458c2ecf20Sopenharmony_ci	return ite;
10468c2ecf20Sopenharmony_ci}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci/*
10498c2ecf20Sopenharmony_ci * The MAPTI and MAPI commands map LPIs to ITTEs.
10508c2ecf20Sopenharmony_ci * Must be called with its_lock mutex held.
10518c2ecf20Sopenharmony_ci */
10528c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
10538c2ecf20Sopenharmony_ci				    u64 *its_cmd)
10548c2ecf20Sopenharmony_ci{
10558c2ecf20Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
10568c2ecf20Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
10578c2ecf20Sopenharmony_ci	u32 coll_id = its_cmd_get_collection(its_cmd);
10588c2ecf20Sopenharmony_ci	struct its_ite *ite;
10598c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu = NULL;
10608c2ecf20Sopenharmony_ci	struct its_device *device;
10618c2ecf20Sopenharmony_ci	struct its_collection *collection, *new_coll = NULL;
10628c2ecf20Sopenharmony_ci	struct vgic_irq *irq;
10638c2ecf20Sopenharmony_ci	int lpi_nr;
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	device = find_its_device(its, device_id);
10668c2ecf20Sopenharmony_ci	if (!device)
10678c2ecf20Sopenharmony_ci		return E_ITS_MAPTI_UNMAPPED_DEVICE;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	if (event_id >= BIT_ULL(device->num_eventid_bits))
10708c2ecf20Sopenharmony_ci		return E_ITS_MAPTI_ID_OOR;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	if (its_cmd_get_command(its_cmd) == GITS_CMD_MAPTI)
10738c2ecf20Sopenharmony_ci		lpi_nr = its_cmd_get_physical_id(its_cmd);
10748c2ecf20Sopenharmony_ci	else
10758c2ecf20Sopenharmony_ci		lpi_nr = event_id;
10768c2ecf20Sopenharmony_ci	if (lpi_nr < GIC_LPI_OFFSET ||
10778c2ecf20Sopenharmony_ci	    lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser))
10788c2ecf20Sopenharmony_ci		return E_ITS_MAPTI_PHYSICALID_OOR;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	/* If there is an existing mapping, behavior is UNPREDICTABLE. */
10818c2ecf20Sopenharmony_ci	if (find_ite(its, device_id, event_id))
10828c2ecf20Sopenharmony_ci		return 0;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	collection = find_collection(its, coll_id);
10858c2ecf20Sopenharmony_ci	if (!collection) {
10868c2ecf20Sopenharmony_ci		int ret = vgic_its_alloc_collection(its, &collection, coll_id);
10878c2ecf20Sopenharmony_ci		if (ret)
10888c2ecf20Sopenharmony_ci			return ret;
10898c2ecf20Sopenharmony_ci		new_coll = collection;
10908c2ecf20Sopenharmony_ci	}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	ite = vgic_its_alloc_ite(device, collection, event_id);
10938c2ecf20Sopenharmony_ci	if (IS_ERR(ite)) {
10948c2ecf20Sopenharmony_ci		if (new_coll)
10958c2ecf20Sopenharmony_ci			vgic_its_free_collection(its, coll_id);
10968c2ecf20Sopenharmony_ci		return PTR_ERR(ite);
10978c2ecf20Sopenharmony_ci	}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	if (its_is_collection_mapped(collection))
11008c2ecf20Sopenharmony_ci		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	irq = vgic_add_lpi(kvm, lpi_nr, vcpu);
11038c2ecf20Sopenharmony_ci	if (IS_ERR(irq)) {
11048c2ecf20Sopenharmony_ci		if (new_coll)
11058c2ecf20Sopenharmony_ci			vgic_its_free_collection(its, coll_id);
11068c2ecf20Sopenharmony_ci		its_free_ite(kvm, ite);
11078c2ecf20Sopenharmony_ci		return PTR_ERR(irq);
11088c2ecf20Sopenharmony_ci	}
11098c2ecf20Sopenharmony_ci	ite->irq = irq;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	return 0;
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci/* Requires the its_lock to be held. */
11158c2ecf20Sopenharmony_cistatic void vgic_its_free_device(struct kvm *kvm, struct its_device *device)
11168c2ecf20Sopenharmony_ci{
11178c2ecf20Sopenharmony_ci	struct its_ite *ite, *temp;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	/*
11208c2ecf20Sopenharmony_ci	 * The spec says that unmapping a device with still valid
11218c2ecf20Sopenharmony_ci	 * ITTEs associated is UNPREDICTABLE. We remove all ITTEs,
11228c2ecf20Sopenharmony_ci	 * since we cannot leave the memory unreferenced.
11238c2ecf20Sopenharmony_ci	 */
11248c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ite, temp, &device->itt_head, ite_list)
11258c2ecf20Sopenharmony_ci		its_free_ite(kvm, ite);
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	vgic_its_invalidate_cache(kvm);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	list_del(&device->dev_list);
11308c2ecf20Sopenharmony_ci	kfree(device);
11318c2ecf20Sopenharmony_ci}
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci/* its lock must be held */
11348c2ecf20Sopenharmony_cistatic void vgic_its_free_device_list(struct kvm *kvm, struct vgic_its *its)
11358c2ecf20Sopenharmony_ci{
11368c2ecf20Sopenharmony_ci	struct its_device *cur, *temp;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cur, temp, &its->device_list, dev_list)
11398c2ecf20Sopenharmony_ci		vgic_its_free_device(kvm, cur);
11408c2ecf20Sopenharmony_ci}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci/* its lock must be held */
11438c2ecf20Sopenharmony_cistatic void vgic_its_free_collection_list(struct kvm *kvm, struct vgic_its *its)
11448c2ecf20Sopenharmony_ci{
11458c2ecf20Sopenharmony_ci	struct its_collection *cur, *temp;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cur, temp, &its->collection_list, coll_list)
11488c2ecf20Sopenharmony_ci		vgic_its_free_collection(its, cur->collection_id);
11498c2ecf20Sopenharmony_ci}
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci/* Must be called with its_lock mutex held */
11528c2ecf20Sopenharmony_cistatic struct its_device *vgic_its_alloc_device(struct vgic_its *its,
11538c2ecf20Sopenharmony_ci						u32 device_id, gpa_t itt_addr,
11548c2ecf20Sopenharmony_ci						u8 num_eventid_bits)
11558c2ecf20Sopenharmony_ci{
11568c2ecf20Sopenharmony_ci	struct its_device *device;
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	device = kzalloc(sizeof(*device), GFP_KERNEL);
11598c2ecf20Sopenharmony_ci	if (!device)
11608c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	device->device_id = device_id;
11638c2ecf20Sopenharmony_ci	device->itt_addr = itt_addr;
11648c2ecf20Sopenharmony_ci	device->num_eventid_bits = num_eventid_bits;
11658c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&device->itt_head);
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	list_add_tail(&device->dev_list, &its->device_list);
11688c2ecf20Sopenharmony_ci	return device;
11698c2ecf20Sopenharmony_ci}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci/*
11728c2ecf20Sopenharmony_ci * MAPD maps or unmaps a device ID to Interrupt Translation Tables (ITTs).
11738c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
11748c2ecf20Sopenharmony_ci */
11758c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
11768c2ecf20Sopenharmony_ci				    u64 *its_cmd)
11778c2ecf20Sopenharmony_ci{
11788c2ecf20Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
11798c2ecf20Sopenharmony_ci	bool valid = its_cmd_get_validbit(its_cmd);
11808c2ecf20Sopenharmony_ci	u8 num_eventid_bits = its_cmd_get_size(its_cmd);
11818c2ecf20Sopenharmony_ci	gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
11828c2ecf20Sopenharmony_ci	struct its_device *device;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	if (!vgic_its_check_id(its, its->baser_device_table, device_id, NULL))
11858c2ecf20Sopenharmony_ci		return E_ITS_MAPD_DEVICE_OOR;
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	if (valid && num_eventid_bits > VITS_TYPER_IDBITS)
11888c2ecf20Sopenharmony_ci		return E_ITS_MAPD_ITTSIZE_OOR;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	device = find_its_device(its, device_id);
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	/*
11938c2ecf20Sopenharmony_ci	 * The spec says that calling MAPD on an already mapped device
11948c2ecf20Sopenharmony_ci	 * invalidates all cached data for this device. We implement this
11958c2ecf20Sopenharmony_ci	 * by removing the mapping and re-establishing it.
11968c2ecf20Sopenharmony_ci	 */
11978c2ecf20Sopenharmony_ci	if (device)
11988c2ecf20Sopenharmony_ci		vgic_its_free_device(kvm, device);
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	/*
12018c2ecf20Sopenharmony_ci	 * The spec does not say whether unmapping a not-mapped device
12028c2ecf20Sopenharmony_ci	 * is an error, so we are done in any case.
12038c2ecf20Sopenharmony_ci	 */
12048c2ecf20Sopenharmony_ci	if (!valid)
12058c2ecf20Sopenharmony_ci		return 0;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	device = vgic_its_alloc_device(its, device_id, itt_addr,
12088c2ecf20Sopenharmony_ci				       num_eventid_bits);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(device);
12118c2ecf20Sopenharmony_ci}
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci/*
12148c2ecf20Sopenharmony_ci * The MAPC command maps collection IDs to redistributors.
12158c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
12168c2ecf20Sopenharmony_ci */
12178c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_mapc(struct kvm *kvm, struct vgic_its *its,
12188c2ecf20Sopenharmony_ci				    u64 *its_cmd)
12198c2ecf20Sopenharmony_ci{
12208c2ecf20Sopenharmony_ci	u16 coll_id;
12218c2ecf20Sopenharmony_ci	u32 target_addr;
12228c2ecf20Sopenharmony_ci	struct its_collection *collection;
12238c2ecf20Sopenharmony_ci	bool valid;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	valid = its_cmd_get_validbit(its_cmd);
12268c2ecf20Sopenharmony_ci	coll_id = its_cmd_get_collection(its_cmd);
12278c2ecf20Sopenharmony_ci	target_addr = its_cmd_get_target_addr(its_cmd);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	if (target_addr >= atomic_read(&kvm->online_vcpus))
12308c2ecf20Sopenharmony_ci		return E_ITS_MAPC_PROCNUM_OOR;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	if (!valid) {
12338c2ecf20Sopenharmony_ci		vgic_its_free_collection(its, coll_id);
12348c2ecf20Sopenharmony_ci		vgic_its_invalidate_cache(kvm);
12358c2ecf20Sopenharmony_ci	} else {
12368c2ecf20Sopenharmony_ci		collection = find_collection(its, coll_id);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci		if (!collection) {
12398c2ecf20Sopenharmony_ci			int ret;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci			ret = vgic_its_alloc_collection(its, &collection,
12428c2ecf20Sopenharmony_ci							coll_id);
12438c2ecf20Sopenharmony_ci			if (ret)
12448c2ecf20Sopenharmony_ci				return ret;
12458c2ecf20Sopenharmony_ci			collection->target_addr = target_addr;
12468c2ecf20Sopenharmony_ci		} else {
12478c2ecf20Sopenharmony_ci			collection->target_addr = target_addr;
12488c2ecf20Sopenharmony_ci			update_affinity_collection(kvm, its, collection);
12498c2ecf20Sopenharmony_ci		}
12508c2ecf20Sopenharmony_ci	}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	return 0;
12538c2ecf20Sopenharmony_ci}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci/*
12568c2ecf20Sopenharmony_ci * The CLEAR command removes the pending state for a particular LPI.
12578c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
12588c2ecf20Sopenharmony_ci */
12598c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_clear(struct kvm *kvm, struct vgic_its *its,
12608c2ecf20Sopenharmony_ci				     u64 *its_cmd)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
12638c2ecf20Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
12648c2ecf20Sopenharmony_ci	struct its_ite *ite;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	ite = find_ite(its, device_id, event_id);
12688c2ecf20Sopenharmony_ci	if (!ite)
12698c2ecf20Sopenharmony_ci		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	ite->irq->pending_latch = false;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	if (ite->irq->hw)
12748c2ecf20Sopenharmony_ci		return irq_set_irqchip_state(ite->irq->host_irq,
12758c2ecf20Sopenharmony_ci					     IRQCHIP_STATE_PENDING, false);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	return 0;
12788c2ecf20Sopenharmony_ci}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci/*
12818c2ecf20Sopenharmony_ci * The INV command syncs the configuration bits from the memory table.
12828c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
12838c2ecf20Sopenharmony_ci */
12848c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_inv(struct kvm *kvm, struct vgic_its *its,
12858c2ecf20Sopenharmony_ci				   u64 *its_cmd)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
12888c2ecf20Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
12898c2ecf20Sopenharmony_ci	struct its_ite *ite;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	ite = find_ite(its, device_id, event_id);
12938c2ecf20Sopenharmony_ci	if (!ite)
12948c2ecf20Sopenharmony_ci		return E_ITS_INV_UNMAPPED_INTERRUPT;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	return update_lpi_config(kvm, ite->irq, NULL, true);
12978c2ecf20Sopenharmony_ci}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci/*
13008c2ecf20Sopenharmony_ci * The INVALL command requests flushing of all IRQ data in this collection.
13018c2ecf20Sopenharmony_ci * Find the VCPU mapped to that collection, then iterate over the VM's list
13028c2ecf20Sopenharmony_ci * of mapped LPIs and update the configuration for each IRQ which targets
13038c2ecf20Sopenharmony_ci * the specified vcpu. The configuration will be read from the in-memory
13048c2ecf20Sopenharmony_ci * configuration table.
13058c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
13068c2ecf20Sopenharmony_ci */
13078c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_invall(struct kvm *kvm, struct vgic_its *its,
13088c2ecf20Sopenharmony_ci				      u64 *its_cmd)
13098c2ecf20Sopenharmony_ci{
13108c2ecf20Sopenharmony_ci	u32 coll_id = its_cmd_get_collection(its_cmd);
13118c2ecf20Sopenharmony_ci	struct its_collection *collection;
13128c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu;
13138c2ecf20Sopenharmony_ci	struct vgic_irq *irq;
13148c2ecf20Sopenharmony_ci	u32 *intids;
13158c2ecf20Sopenharmony_ci	int irq_count, i;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	collection = find_collection(its, coll_id);
13188c2ecf20Sopenharmony_ci	if (!its_is_collection_mapped(collection))
13198c2ecf20Sopenharmony_ci		return E_ITS_INVALL_UNMAPPED_COLLECTION;
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	irq_count = vgic_copy_lpi_list(kvm, vcpu, &intids);
13248c2ecf20Sopenharmony_ci	if (irq_count < 0)
13258c2ecf20Sopenharmony_ci		return irq_count;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	for (i = 0; i < irq_count; i++) {
13288c2ecf20Sopenharmony_ci		irq = vgic_get_irq(kvm, NULL, intids[i]);
13298c2ecf20Sopenharmony_ci		if (!irq)
13308c2ecf20Sopenharmony_ci			continue;
13318c2ecf20Sopenharmony_ci		update_lpi_config(kvm, irq, vcpu, false);
13328c2ecf20Sopenharmony_ci		vgic_put_irq(kvm, irq);
13338c2ecf20Sopenharmony_ci	}
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	kfree(intids);
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.its_vm)
13388c2ecf20Sopenharmony_ci		its_invall_vpe(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe);
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	return 0;
13418c2ecf20Sopenharmony_ci}
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci/*
13448c2ecf20Sopenharmony_ci * The MOVALL command moves the pending state of all IRQs targeting one
13458c2ecf20Sopenharmony_ci * redistributor to another. We don't hold the pending state in the VCPUs,
13468c2ecf20Sopenharmony_ci * but in the IRQs instead, so there is really not much to do for us here.
13478c2ecf20Sopenharmony_ci * However the spec says that no IRQ must target the old redistributor
13488c2ecf20Sopenharmony_ci * afterwards, so we make sure that no LPI is using the associated target_vcpu.
13498c2ecf20Sopenharmony_ci * This command affects all LPIs in the system that target that redistributor.
13508c2ecf20Sopenharmony_ci */
13518c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,
13528c2ecf20Sopenharmony_ci				      u64 *its_cmd)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	u32 target1_addr = its_cmd_get_target_addr(its_cmd);
13558c2ecf20Sopenharmony_ci	u32 target2_addr = its_cmd_mask_field(its_cmd, 3, 16, 32);
13568c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu1, *vcpu2;
13578c2ecf20Sopenharmony_ci	struct vgic_irq *irq;
13588c2ecf20Sopenharmony_ci	u32 *intids;
13598c2ecf20Sopenharmony_ci	int irq_count, i;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	if (target1_addr >= atomic_read(&kvm->online_vcpus) ||
13628c2ecf20Sopenharmony_ci	    target2_addr >= atomic_read(&kvm->online_vcpus))
13638c2ecf20Sopenharmony_ci		return E_ITS_MOVALL_PROCNUM_OOR;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	if (target1_addr == target2_addr)
13668c2ecf20Sopenharmony_ci		return 0;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	vcpu1 = kvm_get_vcpu(kvm, target1_addr);
13698c2ecf20Sopenharmony_ci	vcpu2 = kvm_get_vcpu(kvm, target2_addr);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	irq_count = vgic_copy_lpi_list(kvm, vcpu1, &intids);
13728c2ecf20Sopenharmony_ci	if (irq_count < 0)
13738c2ecf20Sopenharmony_ci		return irq_count;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	for (i = 0; i < irq_count; i++) {
13768c2ecf20Sopenharmony_ci		irq = vgic_get_irq(kvm, NULL, intids[i]);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci		update_affinity(irq, vcpu2);
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci		vgic_put_irq(kvm, irq);
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	vgic_its_invalidate_cache(kvm);
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	kfree(intids);
13868c2ecf20Sopenharmony_ci	return 0;
13878c2ecf20Sopenharmony_ci}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci/*
13908c2ecf20Sopenharmony_ci * The INT command injects the LPI associated with that DevID/EvID pair.
13918c2ecf20Sopenharmony_ci * Must be called with the its_lock mutex held.
13928c2ecf20Sopenharmony_ci */
13938c2ecf20Sopenharmony_cistatic int vgic_its_cmd_handle_int(struct kvm *kvm, struct vgic_its *its,
13948c2ecf20Sopenharmony_ci				   u64 *its_cmd)
13958c2ecf20Sopenharmony_ci{
13968c2ecf20Sopenharmony_ci	u32 msi_data = its_cmd_get_id(its_cmd);
13978c2ecf20Sopenharmony_ci	u64 msi_devid = its_cmd_get_deviceid(its_cmd);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	return vgic_its_trigger_msi(kvm, its, msi_devid, msi_data);
14008c2ecf20Sopenharmony_ci}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci/*
14038c2ecf20Sopenharmony_ci * This function is called with the its_cmd lock held, but the ITS data
14048c2ecf20Sopenharmony_ci * structure lock dropped.
14058c2ecf20Sopenharmony_ci */
14068c2ecf20Sopenharmony_cistatic int vgic_its_handle_command(struct kvm *kvm, struct vgic_its *its,
14078c2ecf20Sopenharmony_ci				   u64 *its_cmd)
14088c2ecf20Sopenharmony_ci{
14098c2ecf20Sopenharmony_ci	int ret = -ENODEV;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	mutex_lock(&its->its_lock);
14128c2ecf20Sopenharmony_ci	switch (its_cmd_get_command(its_cmd)) {
14138c2ecf20Sopenharmony_ci	case GITS_CMD_MAPD:
14148c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_mapd(kvm, its, its_cmd);
14158c2ecf20Sopenharmony_ci		break;
14168c2ecf20Sopenharmony_ci	case GITS_CMD_MAPC:
14178c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_mapc(kvm, its, its_cmd);
14188c2ecf20Sopenharmony_ci		break;
14198c2ecf20Sopenharmony_ci	case GITS_CMD_MAPI:
14208c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_mapi(kvm, its, its_cmd);
14218c2ecf20Sopenharmony_ci		break;
14228c2ecf20Sopenharmony_ci	case GITS_CMD_MAPTI:
14238c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_mapi(kvm, its, its_cmd);
14248c2ecf20Sopenharmony_ci		break;
14258c2ecf20Sopenharmony_ci	case GITS_CMD_MOVI:
14268c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_movi(kvm, its, its_cmd);
14278c2ecf20Sopenharmony_ci		break;
14288c2ecf20Sopenharmony_ci	case GITS_CMD_DISCARD:
14298c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_discard(kvm, its, its_cmd);
14308c2ecf20Sopenharmony_ci		break;
14318c2ecf20Sopenharmony_ci	case GITS_CMD_CLEAR:
14328c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_clear(kvm, its, its_cmd);
14338c2ecf20Sopenharmony_ci		break;
14348c2ecf20Sopenharmony_ci	case GITS_CMD_MOVALL:
14358c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_movall(kvm, its, its_cmd);
14368c2ecf20Sopenharmony_ci		break;
14378c2ecf20Sopenharmony_ci	case GITS_CMD_INT:
14388c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_int(kvm, its, its_cmd);
14398c2ecf20Sopenharmony_ci		break;
14408c2ecf20Sopenharmony_ci	case GITS_CMD_INV:
14418c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_inv(kvm, its, its_cmd);
14428c2ecf20Sopenharmony_ci		break;
14438c2ecf20Sopenharmony_ci	case GITS_CMD_INVALL:
14448c2ecf20Sopenharmony_ci		ret = vgic_its_cmd_handle_invall(kvm, its, its_cmd);
14458c2ecf20Sopenharmony_ci		break;
14468c2ecf20Sopenharmony_ci	case GITS_CMD_SYNC:
14478c2ecf20Sopenharmony_ci		/* we ignore this command: we are in sync all of the time */
14488c2ecf20Sopenharmony_ci		ret = 0;
14498c2ecf20Sopenharmony_ci		break;
14508c2ecf20Sopenharmony_ci	}
14518c2ecf20Sopenharmony_ci	mutex_unlock(&its->its_lock);
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	return ret;
14548c2ecf20Sopenharmony_ci}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_cistatic u64 vgic_sanitise_its_baser(u64 reg)
14578c2ecf20Sopenharmony_ci{
14588c2ecf20Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_BASER_SHAREABILITY_MASK,
14598c2ecf20Sopenharmony_ci				  GITS_BASER_SHAREABILITY_SHIFT,
14608c2ecf20Sopenharmony_ci				  vgic_sanitise_shareability);
14618c2ecf20Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_BASER_INNER_CACHEABILITY_MASK,
14628c2ecf20Sopenharmony_ci				  GITS_BASER_INNER_CACHEABILITY_SHIFT,
14638c2ecf20Sopenharmony_ci				  vgic_sanitise_inner_cacheability);
14648c2ecf20Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_BASER_OUTER_CACHEABILITY_MASK,
14658c2ecf20Sopenharmony_ci				  GITS_BASER_OUTER_CACHEABILITY_SHIFT,
14668c2ecf20Sopenharmony_ci				  vgic_sanitise_outer_cacheability);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	/* We support only one (ITS) page size: 64K */
14698c2ecf20Sopenharmony_ci	reg = (reg & ~GITS_BASER_PAGE_SIZE_MASK) | GITS_BASER_PAGE_SIZE_64K;
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	return reg;
14728c2ecf20Sopenharmony_ci}
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_cistatic u64 vgic_sanitise_its_cbaser(u64 reg)
14758c2ecf20Sopenharmony_ci{
14768c2ecf20Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_CBASER_SHAREABILITY_MASK,
14778c2ecf20Sopenharmony_ci				  GITS_CBASER_SHAREABILITY_SHIFT,
14788c2ecf20Sopenharmony_ci				  vgic_sanitise_shareability);
14798c2ecf20Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_CBASER_INNER_CACHEABILITY_MASK,
14808c2ecf20Sopenharmony_ci				  GITS_CBASER_INNER_CACHEABILITY_SHIFT,
14818c2ecf20Sopenharmony_ci				  vgic_sanitise_inner_cacheability);
14828c2ecf20Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_CBASER_OUTER_CACHEABILITY_MASK,
14838c2ecf20Sopenharmony_ci				  GITS_CBASER_OUTER_CACHEABILITY_SHIFT,
14848c2ecf20Sopenharmony_ci				  vgic_sanitise_outer_cacheability);
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	/* Sanitise the physical address to be 64k aligned. */
14878c2ecf20Sopenharmony_ci	reg &= ~GENMASK_ULL(15, 12);
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	return reg;
14908c2ecf20Sopenharmony_ci}
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_cistatic unsigned long vgic_mmio_read_its_cbaser(struct kvm *kvm,
14938c2ecf20Sopenharmony_ci					       struct vgic_its *its,
14948c2ecf20Sopenharmony_ci					       gpa_t addr, unsigned int len)
14958c2ecf20Sopenharmony_ci{
14968c2ecf20Sopenharmony_ci	return extract_bytes(its->cbaser, addr & 7, len);
14978c2ecf20Sopenharmony_ci}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_cistatic void vgic_mmio_write_its_cbaser(struct kvm *kvm, struct vgic_its *its,
15008c2ecf20Sopenharmony_ci				       gpa_t addr, unsigned int len,
15018c2ecf20Sopenharmony_ci				       unsigned long val)
15028c2ecf20Sopenharmony_ci{
15038c2ecf20Sopenharmony_ci	/* When GITS_CTLR.Enable is 1, this register is RO. */
15048c2ecf20Sopenharmony_ci	if (its->enabled)
15058c2ecf20Sopenharmony_ci		return;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	mutex_lock(&its->cmd_lock);
15088c2ecf20Sopenharmony_ci	its->cbaser = update_64bit_reg(its->cbaser, addr & 7, len, val);
15098c2ecf20Sopenharmony_ci	its->cbaser = vgic_sanitise_its_cbaser(its->cbaser);
15108c2ecf20Sopenharmony_ci	its->creadr = 0;
15118c2ecf20Sopenharmony_ci	/*
15128c2ecf20Sopenharmony_ci	 * CWRITER is architecturally UNKNOWN on reset, but we need to reset
15138c2ecf20Sopenharmony_ci	 * it to CREADR to make sure we start with an empty command buffer.
15148c2ecf20Sopenharmony_ci	 */
15158c2ecf20Sopenharmony_ci	its->cwriter = its->creadr;
15168c2ecf20Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
15178c2ecf20Sopenharmony_ci}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci#define ITS_CMD_BUFFER_SIZE(baser)	((((baser) & 0xff) + 1) << 12)
15208c2ecf20Sopenharmony_ci#define ITS_CMD_SIZE			32
15218c2ecf20Sopenharmony_ci#define ITS_CMD_OFFSET(reg)		((reg) & GENMASK(19, 5))
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci/* Must be called with the cmd_lock held. */
15248c2ecf20Sopenharmony_cistatic void vgic_its_process_commands(struct kvm *kvm, struct vgic_its *its)
15258c2ecf20Sopenharmony_ci{
15268c2ecf20Sopenharmony_ci	gpa_t cbaser;
15278c2ecf20Sopenharmony_ci	u64 cmd_buf[4];
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	/* Commands are only processed when the ITS is enabled. */
15308c2ecf20Sopenharmony_ci	if (!its->enabled)
15318c2ecf20Sopenharmony_ci		return;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	cbaser = GITS_CBASER_ADDRESS(its->cbaser);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	while (its->cwriter != its->creadr) {
15368c2ecf20Sopenharmony_ci		int ret = kvm_read_guest_lock(kvm, cbaser + its->creadr,
15378c2ecf20Sopenharmony_ci					      cmd_buf, ITS_CMD_SIZE);
15388c2ecf20Sopenharmony_ci		/*
15398c2ecf20Sopenharmony_ci		 * If kvm_read_guest() fails, this could be due to the guest
15408c2ecf20Sopenharmony_ci		 * programming a bogus value in CBASER or something else going
15418c2ecf20Sopenharmony_ci		 * wrong from which we cannot easily recover.
15428c2ecf20Sopenharmony_ci		 * According to section 6.3.2 in the GICv3 spec we can just
15438c2ecf20Sopenharmony_ci		 * ignore that command then.
15448c2ecf20Sopenharmony_ci		 */
15458c2ecf20Sopenharmony_ci		if (!ret)
15468c2ecf20Sopenharmony_ci			vgic_its_handle_command(kvm, its, cmd_buf);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci		its->creadr += ITS_CMD_SIZE;
15498c2ecf20Sopenharmony_ci		if (its->creadr == ITS_CMD_BUFFER_SIZE(its->cbaser))
15508c2ecf20Sopenharmony_ci			its->creadr = 0;
15518c2ecf20Sopenharmony_ci	}
15528c2ecf20Sopenharmony_ci}
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci/*
15558c2ecf20Sopenharmony_ci * By writing to CWRITER the guest announces new commands to be processed.
15568c2ecf20Sopenharmony_ci * To avoid any races in the first place, we take the its_cmd lock, which
15578c2ecf20Sopenharmony_ci * protects our ring buffer variables, so that there is only one user
15588c2ecf20Sopenharmony_ci * per ITS handling commands at a given time.
15598c2ecf20Sopenharmony_ci */
15608c2ecf20Sopenharmony_cistatic void vgic_mmio_write_its_cwriter(struct kvm *kvm, struct vgic_its *its,
15618c2ecf20Sopenharmony_ci					gpa_t addr, unsigned int len,
15628c2ecf20Sopenharmony_ci					unsigned long val)
15638c2ecf20Sopenharmony_ci{
15648c2ecf20Sopenharmony_ci	u64 reg;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	if (!its)
15678c2ecf20Sopenharmony_ci		return;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	mutex_lock(&its->cmd_lock);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	reg = update_64bit_reg(its->cwriter, addr & 7, len, val);
15728c2ecf20Sopenharmony_ci	reg = ITS_CMD_OFFSET(reg);
15738c2ecf20Sopenharmony_ci	if (reg >= ITS_CMD_BUFFER_SIZE(its->cbaser)) {
15748c2ecf20Sopenharmony_ci		mutex_unlock(&its->cmd_lock);
15758c2ecf20Sopenharmony_ci		return;
15768c2ecf20Sopenharmony_ci	}
15778c2ecf20Sopenharmony_ci	its->cwriter = reg;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	vgic_its_process_commands(kvm, its);
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
15828c2ecf20Sopenharmony_ci}
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_cistatic unsigned long vgic_mmio_read_its_cwriter(struct kvm *kvm,
15858c2ecf20Sopenharmony_ci						struct vgic_its *its,
15868c2ecf20Sopenharmony_ci						gpa_t addr, unsigned int len)
15878c2ecf20Sopenharmony_ci{
15888c2ecf20Sopenharmony_ci	return extract_bytes(its->cwriter, addr & 0x7, len);
15898c2ecf20Sopenharmony_ci}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_cistatic unsigned long vgic_mmio_read_its_creadr(struct kvm *kvm,
15928c2ecf20Sopenharmony_ci					       struct vgic_its *its,
15938c2ecf20Sopenharmony_ci					       gpa_t addr, unsigned int len)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	return extract_bytes(its->creadr, addr & 0x7, len);
15968c2ecf20Sopenharmony_ci}
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_cistatic int vgic_mmio_uaccess_write_its_creadr(struct kvm *kvm,
15998c2ecf20Sopenharmony_ci					      struct vgic_its *its,
16008c2ecf20Sopenharmony_ci					      gpa_t addr, unsigned int len,
16018c2ecf20Sopenharmony_ci					      unsigned long val)
16028c2ecf20Sopenharmony_ci{
16038c2ecf20Sopenharmony_ci	u32 cmd_offset;
16048c2ecf20Sopenharmony_ci	int ret = 0;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	mutex_lock(&its->cmd_lock);
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	if (its->enabled) {
16098c2ecf20Sopenharmony_ci		ret = -EBUSY;
16108c2ecf20Sopenharmony_ci		goto out;
16118c2ecf20Sopenharmony_ci	}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	cmd_offset = ITS_CMD_OFFSET(val);
16148c2ecf20Sopenharmony_ci	if (cmd_offset >= ITS_CMD_BUFFER_SIZE(its->cbaser)) {
16158c2ecf20Sopenharmony_ci		ret = -EINVAL;
16168c2ecf20Sopenharmony_ci		goto out;
16178c2ecf20Sopenharmony_ci	}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	its->creadr = cmd_offset;
16208c2ecf20Sopenharmony_ciout:
16218c2ecf20Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
16228c2ecf20Sopenharmony_ci	return ret;
16238c2ecf20Sopenharmony_ci}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci#define BASER_INDEX(addr) (((addr) / sizeof(u64)) & 0x7)
16268c2ecf20Sopenharmony_cistatic unsigned long vgic_mmio_read_its_baser(struct kvm *kvm,
16278c2ecf20Sopenharmony_ci					      struct vgic_its *its,
16288c2ecf20Sopenharmony_ci					      gpa_t addr, unsigned int len)
16298c2ecf20Sopenharmony_ci{
16308c2ecf20Sopenharmony_ci	u64 reg;
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	switch (BASER_INDEX(addr)) {
16338c2ecf20Sopenharmony_ci	case 0:
16348c2ecf20Sopenharmony_ci		reg = its->baser_device_table;
16358c2ecf20Sopenharmony_ci		break;
16368c2ecf20Sopenharmony_ci	case 1:
16378c2ecf20Sopenharmony_ci		reg = its->baser_coll_table;
16388c2ecf20Sopenharmony_ci		break;
16398c2ecf20Sopenharmony_ci	default:
16408c2ecf20Sopenharmony_ci		reg = 0;
16418c2ecf20Sopenharmony_ci		break;
16428c2ecf20Sopenharmony_ci	}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	return extract_bytes(reg, addr & 7, len);
16458c2ecf20Sopenharmony_ci}
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci#define GITS_BASER_RO_MASK	(GENMASK_ULL(52, 48) | GENMASK_ULL(58, 56))
16488c2ecf20Sopenharmony_cistatic void vgic_mmio_write_its_baser(struct kvm *kvm,
16498c2ecf20Sopenharmony_ci				      struct vgic_its *its,
16508c2ecf20Sopenharmony_ci				      gpa_t addr, unsigned int len,
16518c2ecf20Sopenharmony_ci				      unsigned long val)
16528c2ecf20Sopenharmony_ci{
16538c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
16548c2ecf20Sopenharmony_ci	u64 entry_size, table_type;
16558c2ecf20Sopenharmony_ci	u64 reg, *regptr, clearbits = 0;
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	/* When GITS_CTLR.Enable is 1, we ignore write accesses. */
16588c2ecf20Sopenharmony_ci	if (its->enabled)
16598c2ecf20Sopenharmony_ci		return;
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	switch (BASER_INDEX(addr)) {
16628c2ecf20Sopenharmony_ci	case 0:
16638c2ecf20Sopenharmony_ci		regptr = &its->baser_device_table;
16648c2ecf20Sopenharmony_ci		entry_size = abi->dte_esz;
16658c2ecf20Sopenharmony_ci		table_type = GITS_BASER_TYPE_DEVICE;
16668c2ecf20Sopenharmony_ci		break;
16678c2ecf20Sopenharmony_ci	case 1:
16688c2ecf20Sopenharmony_ci		regptr = &its->baser_coll_table;
16698c2ecf20Sopenharmony_ci		entry_size = abi->cte_esz;
16708c2ecf20Sopenharmony_ci		table_type = GITS_BASER_TYPE_COLLECTION;
16718c2ecf20Sopenharmony_ci		clearbits = GITS_BASER_INDIRECT;
16728c2ecf20Sopenharmony_ci		break;
16738c2ecf20Sopenharmony_ci	default:
16748c2ecf20Sopenharmony_ci		return;
16758c2ecf20Sopenharmony_ci	}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	reg = update_64bit_reg(*regptr, addr & 7, len, val);
16788c2ecf20Sopenharmony_ci	reg &= ~GITS_BASER_RO_MASK;
16798c2ecf20Sopenharmony_ci	reg &= ~clearbits;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	reg |= (entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT;
16828c2ecf20Sopenharmony_ci	reg |= table_type << GITS_BASER_TYPE_SHIFT;
16838c2ecf20Sopenharmony_ci	reg = vgic_sanitise_its_baser(reg);
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	*regptr = reg;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	if (!(reg & GITS_BASER_VALID)) {
16888c2ecf20Sopenharmony_ci		/* Take the its_lock to prevent a race with a save/restore */
16898c2ecf20Sopenharmony_ci		mutex_lock(&its->its_lock);
16908c2ecf20Sopenharmony_ci		switch (table_type) {
16918c2ecf20Sopenharmony_ci		case GITS_BASER_TYPE_DEVICE:
16928c2ecf20Sopenharmony_ci			vgic_its_free_device_list(kvm, its);
16938c2ecf20Sopenharmony_ci			break;
16948c2ecf20Sopenharmony_ci		case GITS_BASER_TYPE_COLLECTION:
16958c2ecf20Sopenharmony_ci			vgic_its_free_collection_list(kvm, its);
16968c2ecf20Sopenharmony_ci			break;
16978c2ecf20Sopenharmony_ci		}
16988c2ecf20Sopenharmony_ci		mutex_unlock(&its->its_lock);
16998c2ecf20Sopenharmony_ci	}
17008c2ecf20Sopenharmony_ci}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_cistatic unsigned long vgic_mmio_read_its_ctlr(struct kvm *vcpu,
17038c2ecf20Sopenharmony_ci					     struct vgic_its *its,
17048c2ecf20Sopenharmony_ci					     gpa_t addr, unsigned int len)
17058c2ecf20Sopenharmony_ci{
17068c2ecf20Sopenharmony_ci	u32 reg = 0;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	mutex_lock(&its->cmd_lock);
17098c2ecf20Sopenharmony_ci	if (its->creadr == its->cwriter)
17108c2ecf20Sopenharmony_ci		reg |= GITS_CTLR_QUIESCENT;
17118c2ecf20Sopenharmony_ci	if (its->enabled)
17128c2ecf20Sopenharmony_ci		reg |= GITS_CTLR_ENABLE;
17138c2ecf20Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	return reg;
17168c2ecf20Sopenharmony_ci}
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_cistatic void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
17198c2ecf20Sopenharmony_ci				     gpa_t addr, unsigned int len,
17208c2ecf20Sopenharmony_ci				     unsigned long val)
17218c2ecf20Sopenharmony_ci{
17228c2ecf20Sopenharmony_ci	mutex_lock(&its->cmd_lock);
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	/*
17258c2ecf20Sopenharmony_ci	 * It is UNPREDICTABLE to enable the ITS if any of the CBASER or
17268c2ecf20Sopenharmony_ci	 * device/collection BASER are invalid
17278c2ecf20Sopenharmony_ci	 */
17288c2ecf20Sopenharmony_ci	if (!its->enabled && (val & GITS_CTLR_ENABLE) &&
17298c2ecf20Sopenharmony_ci		(!(its->baser_device_table & GITS_BASER_VALID) ||
17308c2ecf20Sopenharmony_ci		 !(its->baser_coll_table & GITS_BASER_VALID) ||
17318c2ecf20Sopenharmony_ci		 !(its->cbaser & GITS_CBASER_VALID)))
17328c2ecf20Sopenharmony_ci		goto out;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	its->enabled = !!(val & GITS_CTLR_ENABLE);
17358c2ecf20Sopenharmony_ci	if (!its->enabled)
17368c2ecf20Sopenharmony_ci		vgic_its_invalidate_cache(kvm);
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	/*
17398c2ecf20Sopenharmony_ci	 * Try to process any pending commands. This function bails out early
17408c2ecf20Sopenharmony_ci	 * if the ITS is disabled or no commands have been queued.
17418c2ecf20Sopenharmony_ci	 */
17428c2ecf20Sopenharmony_ci	vgic_its_process_commands(kvm, its);
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ciout:
17458c2ecf20Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
17468c2ecf20Sopenharmony_ci}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci#define REGISTER_ITS_DESC(off, rd, wr, length, acc)		\
17498c2ecf20Sopenharmony_ci{								\
17508c2ecf20Sopenharmony_ci	.reg_offset = off,					\
17518c2ecf20Sopenharmony_ci	.len = length,						\
17528c2ecf20Sopenharmony_ci	.access_flags = acc,					\
17538c2ecf20Sopenharmony_ci	.its_read = rd,						\
17548c2ecf20Sopenharmony_ci	.its_write = wr,					\
17558c2ecf20Sopenharmony_ci}
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci#define REGISTER_ITS_DESC_UACCESS(off, rd, wr, uwr, length, acc)\
17588c2ecf20Sopenharmony_ci{								\
17598c2ecf20Sopenharmony_ci	.reg_offset = off,					\
17608c2ecf20Sopenharmony_ci	.len = length,						\
17618c2ecf20Sopenharmony_ci	.access_flags = acc,					\
17628c2ecf20Sopenharmony_ci	.its_read = rd,						\
17638c2ecf20Sopenharmony_ci	.its_write = wr,					\
17648c2ecf20Sopenharmony_ci	.uaccess_its_write = uwr,				\
17658c2ecf20Sopenharmony_ci}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_cistatic void its_mmio_write_wi(struct kvm *kvm, struct vgic_its *its,
17688c2ecf20Sopenharmony_ci			      gpa_t addr, unsigned int len, unsigned long val)
17698c2ecf20Sopenharmony_ci{
17708c2ecf20Sopenharmony_ci	/* Ignore */
17718c2ecf20Sopenharmony_ci}
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_cistatic struct vgic_register_region its_registers[] = {
17748c2ecf20Sopenharmony_ci	REGISTER_ITS_DESC(GITS_CTLR,
17758c2ecf20Sopenharmony_ci		vgic_mmio_read_its_ctlr, vgic_mmio_write_its_ctlr, 4,
17768c2ecf20Sopenharmony_ci		VGIC_ACCESS_32bit),
17778c2ecf20Sopenharmony_ci	REGISTER_ITS_DESC_UACCESS(GITS_IIDR,
17788c2ecf20Sopenharmony_ci		vgic_mmio_read_its_iidr, its_mmio_write_wi,
17798c2ecf20Sopenharmony_ci		vgic_mmio_uaccess_write_its_iidr, 4,
17808c2ecf20Sopenharmony_ci		VGIC_ACCESS_32bit),
17818c2ecf20Sopenharmony_ci	REGISTER_ITS_DESC(GITS_TYPER,
17828c2ecf20Sopenharmony_ci		vgic_mmio_read_its_typer, its_mmio_write_wi, 8,
17838c2ecf20Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
17848c2ecf20Sopenharmony_ci	REGISTER_ITS_DESC(GITS_CBASER,
17858c2ecf20Sopenharmony_ci		vgic_mmio_read_its_cbaser, vgic_mmio_write_its_cbaser, 8,
17868c2ecf20Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
17878c2ecf20Sopenharmony_ci	REGISTER_ITS_DESC(GITS_CWRITER,
17888c2ecf20Sopenharmony_ci		vgic_mmio_read_its_cwriter, vgic_mmio_write_its_cwriter, 8,
17898c2ecf20Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
17908c2ecf20Sopenharmony_ci	REGISTER_ITS_DESC_UACCESS(GITS_CREADR,
17918c2ecf20Sopenharmony_ci		vgic_mmio_read_its_creadr, its_mmio_write_wi,
17928c2ecf20Sopenharmony_ci		vgic_mmio_uaccess_write_its_creadr, 8,
17938c2ecf20Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
17948c2ecf20Sopenharmony_ci	REGISTER_ITS_DESC(GITS_BASER,
17958c2ecf20Sopenharmony_ci		vgic_mmio_read_its_baser, vgic_mmio_write_its_baser, 0x40,
17968c2ecf20Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
17978c2ecf20Sopenharmony_ci	REGISTER_ITS_DESC(GITS_IDREGS_BASE,
17988c2ecf20Sopenharmony_ci		vgic_mmio_read_its_idregs, its_mmio_write_wi, 0x30,
17998c2ecf20Sopenharmony_ci		VGIC_ACCESS_32bit),
18008c2ecf20Sopenharmony_ci};
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci/* This is called on setting the LPI enable bit in the redistributor. */
18038c2ecf20Sopenharmony_civoid vgic_enable_lpis(struct kvm_vcpu *vcpu)
18048c2ecf20Sopenharmony_ci{
18058c2ecf20Sopenharmony_ci	if (!(vcpu->arch.vgic_cpu.pendbaser & GICR_PENDBASER_PTZ))
18068c2ecf20Sopenharmony_ci		its_sync_lpi_pending_table(vcpu);
18078c2ecf20Sopenharmony_ci}
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_cistatic int vgic_register_its_iodev(struct kvm *kvm, struct vgic_its *its,
18108c2ecf20Sopenharmony_ci				   u64 addr)
18118c2ecf20Sopenharmony_ci{
18128c2ecf20Sopenharmony_ci	struct vgic_io_device *iodev = &its->iodev;
18138c2ecf20Sopenharmony_ci	int ret;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	mutex_lock(&kvm->slots_lock);
18168c2ecf20Sopenharmony_ci	if (!IS_VGIC_ADDR_UNDEF(its->vgic_its_base)) {
18178c2ecf20Sopenharmony_ci		ret = -EBUSY;
18188c2ecf20Sopenharmony_ci		goto out;
18198c2ecf20Sopenharmony_ci	}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	its->vgic_its_base = addr;
18228c2ecf20Sopenharmony_ci	iodev->regions = its_registers;
18238c2ecf20Sopenharmony_ci	iodev->nr_regions = ARRAY_SIZE(its_registers);
18248c2ecf20Sopenharmony_ci	kvm_iodevice_init(&iodev->dev, &kvm_io_gic_ops);
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	iodev->base_addr = its->vgic_its_base;
18278c2ecf20Sopenharmony_ci	iodev->iodev_type = IODEV_ITS;
18288c2ecf20Sopenharmony_ci	iodev->its = its;
18298c2ecf20Sopenharmony_ci	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, iodev->base_addr,
18308c2ecf20Sopenharmony_ci				      KVM_VGIC_V3_ITS_SIZE, &iodev->dev);
18318c2ecf20Sopenharmony_ciout:
18328c2ecf20Sopenharmony_ci	mutex_unlock(&kvm->slots_lock);
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	return ret;
18358c2ecf20Sopenharmony_ci}
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci/* Default is 16 cached LPIs per vcpu */
18388c2ecf20Sopenharmony_ci#define LPI_DEFAULT_PCPU_CACHE_SIZE	16
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_civoid vgic_lpi_translation_cache_init(struct kvm *kvm)
18418c2ecf20Sopenharmony_ci{
18428c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
18438c2ecf20Sopenharmony_ci	unsigned int sz;
18448c2ecf20Sopenharmony_ci	int i;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	if (!list_empty(&dist->lpi_translation_cache))
18478c2ecf20Sopenharmony_ci		return;
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci	sz = atomic_read(&kvm->online_vcpus) * LPI_DEFAULT_PCPU_CACHE_SIZE;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	for (i = 0; i < sz; i++) {
18528c2ecf20Sopenharmony_ci		struct vgic_translation_cache_entry *cte;
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci		/* An allocation failure is not fatal */
18558c2ecf20Sopenharmony_ci		cte = kzalloc(sizeof(*cte), GFP_KERNEL);
18568c2ecf20Sopenharmony_ci		if (WARN_ON(!cte))
18578c2ecf20Sopenharmony_ci			break;
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&cte->entry);
18608c2ecf20Sopenharmony_ci		list_add(&cte->entry, &dist->lpi_translation_cache);
18618c2ecf20Sopenharmony_ci	}
18628c2ecf20Sopenharmony_ci}
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_civoid vgic_lpi_translation_cache_destroy(struct kvm *kvm)
18658c2ecf20Sopenharmony_ci{
18668c2ecf20Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
18678c2ecf20Sopenharmony_ci	struct vgic_translation_cache_entry *cte, *tmp;
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	vgic_its_invalidate_cache(kvm);
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cte, tmp,
18728c2ecf20Sopenharmony_ci				 &dist->lpi_translation_cache, entry) {
18738c2ecf20Sopenharmony_ci		list_del(&cte->entry);
18748c2ecf20Sopenharmony_ci		kfree(cte);
18758c2ecf20Sopenharmony_ci	}
18768c2ecf20Sopenharmony_ci}
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci#define INITIAL_BASER_VALUE						  \
18798c2ecf20Sopenharmony_ci	(GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb)		| \
18808c2ecf20Sopenharmony_ci	 GIC_BASER_CACHEABILITY(GITS_BASER, OUTER, SameAsInner)		| \
18818c2ecf20Sopenharmony_ci	 GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)		| \
18828c2ecf20Sopenharmony_ci	 GITS_BASER_PAGE_SIZE_64K)
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci#define INITIAL_PROPBASER_VALUE						  \
18858c2ecf20Sopenharmony_ci	(GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWb)		| \
18868c2ecf20Sopenharmony_ci	 GIC_BASER_CACHEABILITY(GICR_PROPBASER, OUTER, SameAsInner)	| \
18878c2ecf20Sopenharmony_ci	 GIC_BASER_SHAREABILITY(GICR_PROPBASER, InnerShareable))
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_cistatic int vgic_its_create(struct kvm_device *dev, u32 type)
18908c2ecf20Sopenharmony_ci{
18918c2ecf20Sopenharmony_ci	struct vgic_its *its;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	if (type != KVM_DEV_TYPE_ARM_VGIC_ITS)
18948c2ecf20Sopenharmony_ci		return -ENODEV;
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	its = kzalloc(sizeof(struct vgic_its), GFP_KERNEL);
18978c2ecf20Sopenharmony_ci	if (!its)
18988c2ecf20Sopenharmony_ci		return -ENOMEM;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	if (vgic_initialized(dev->kvm)) {
19018c2ecf20Sopenharmony_ci		int ret = vgic_v4_init(dev->kvm);
19028c2ecf20Sopenharmony_ci		if (ret < 0) {
19038c2ecf20Sopenharmony_ci			kfree(its);
19048c2ecf20Sopenharmony_ci			return ret;
19058c2ecf20Sopenharmony_ci		}
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci		vgic_lpi_translation_cache_init(dev->kvm);
19088c2ecf20Sopenharmony_ci	}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	mutex_init(&its->its_lock);
19118c2ecf20Sopenharmony_ci	mutex_init(&its->cmd_lock);
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	its->vgic_its_base = VGIC_ADDR_UNDEF;
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&its->device_list);
19168c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&its->collection_list);
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	dev->kvm->arch.vgic.msis_require_devid = true;
19198c2ecf20Sopenharmony_ci	dev->kvm->arch.vgic.has_its = true;
19208c2ecf20Sopenharmony_ci	its->enabled = false;
19218c2ecf20Sopenharmony_ci	its->dev = dev;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	its->baser_device_table = INITIAL_BASER_VALUE			|
19248c2ecf20Sopenharmony_ci		((u64)GITS_BASER_TYPE_DEVICE << GITS_BASER_TYPE_SHIFT);
19258c2ecf20Sopenharmony_ci	its->baser_coll_table = INITIAL_BASER_VALUE |
19268c2ecf20Sopenharmony_ci		((u64)GITS_BASER_TYPE_COLLECTION << GITS_BASER_TYPE_SHIFT);
19278c2ecf20Sopenharmony_ci	dev->kvm->arch.vgic.propbaser = INITIAL_PROPBASER_VALUE;
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	dev->private = its;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	return vgic_its_set_abi(its, NR_ITS_ABIS - 1);
19328c2ecf20Sopenharmony_ci}
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_cistatic void vgic_its_destroy(struct kvm_device *kvm_dev)
19358c2ecf20Sopenharmony_ci{
19368c2ecf20Sopenharmony_ci	struct kvm *kvm = kvm_dev->kvm;
19378c2ecf20Sopenharmony_ci	struct vgic_its *its = kvm_dev->private;
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	mutex_lock(&its->its_lock);
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	vgic_its_free_device_list(kvm, its);
19428c2ecf20Sopenharmony_ci	vgic_its_free_collection_list(kvm, its);
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	mutex_unlock(&its->its_lock);
19458c2ecf20Sopenharmony_ci	kfree(its);
19468c2ecf20Sopenharmony_ci	kfree(kvm_dev);/* alloc by kvm_ioctl_create_device, free by .destroy */
19478c2ecf20Sopenharmony_ci}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_cistatic int vgic_its_has_attr_regs(struct kvm_device *dev,
19508c2ecf20Sopenharmony_ci				  struct kvm_device_attr *attr)
19518c2ecf20Sopenharmony_ci{
19528c2ecf20Sopenharmony_ci	const struct vgic_register_region *region;
19538c2ecf20Sopenharmony_ci	gpa_t offset = attr->attr;
19548c2ecf20Sopenharmony_ci	int align;
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	align = (offset < GITS_TYPER) || (offset >= GITS_PIDR4) ? 0x3 : 0x7;
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ci	if (offset & align)
19598c2ecf20Sopenharmony_ci		return -EINVAL;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	region = vgic_find_mmio_region(its_registers,
19628c2ecf20Sopenharmony_ci				       ARRAY_SIZE(its_registers),
19638c2ecf20Sopenharmony_ci				       offset);
19648c2ecf20Sopenharmony_ci	if (!region)
19658c2ecf20Sopenharmony_ci		return -ENXIO;
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	return 0;
19688c2ecf20Sopenharmony_ci}
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_cistatic int vgic_its_attr_regs_access(struct kvm_device *dev,
19718c2ecf20Sopenharmony_ci				     struct kvm_device_attr *attr,
19728c2ecf20Sopenharmony_ci				     u64 *reg, bool is_write)
19738c2ecf20Sopenharmony_ci{
19748c2ecf20Sopenharmony_ci	const struct vgic_register_region *region;
19758c2ecf20Sopenharmony_ci	struct vgic_its *its;
19768c2ecf20Sopenharmony_ci	gpa_t addr, offset;
19778c2ecf20Sopenharmony_ci	unsigned int len;
19788c2ecf20Sopenharmony_ci	int align, ret = 0;
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	its = dev->private;
19818c2ecf20Sopenharmony_ci	offset = attr->attr;
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	/*
19848c2ecf20Sopenharmony_ci	 * Although the spec supports upper/lower 32-bit accesses to
19858c2ecf20Sopenharmony_ci	 * 64-bit ITS registers, the userspace ABI requires 64-bit
19868c2ecf20Sopenharmony_ci	 * accesses to all 64-bit wide registers. We therefore only
19878c2ecf20Sopenharmony_ci	 * support 32-bit accesses to GITS_CTLR, GITS_IIDR and GITS ID
19888c2ecf20Sopenharmony_ci	 * registers
19898c2ecf20Sopenharmony_ci	 */
19908c2ecf20Sopenharmony_ci	if ((offset < GITS_TYPER) || (offset >= GITS_PIDR4))
19918c2ecf20Sopenharmony_ci		align = 0x3;
19928c2ecf20Sopenharmony_ci	else
19938c2ecf20Sopenharmony_ci		align = 0x7;
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	if (offset & align)
19968c2ecf20Sopenharmony_ci		return -EINVAL;
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	mutex_lock(&dev->kvm->lock);
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base)) {
20018c2ecf20Sopenharmony_ci		ret = -ENXIO;
20028c2ecf20Sopenharmony_ci		goto out;
20038c2ecf20Sopenharmony_ci	}
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci	region = vgic_find_mmio_region(its_registers,
20068c2ecf20Sopenharmony_ci				       ARRAY_SIZE(its_registers),
20078c2ecf20Sopenharmony_ci				       offset);
20088c2ecf20Sopenharmony_ci	if (!region) {
20098c2ecf20Sopenharmony_ci		ret = -ENXIO;
20108c2ecf20Sopenharmony_ci		goto out;
20118c2ecf20Sopenharmony_ci	}
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	if (!lock_all_vcpus(dev->kvm)) {
20148c2ecf20Sopenharmony_ci		ret = -EBUSY;
20158c2ecf20Sopenharmony_ci		goto out;
20168c2ecf20Sopenharmony_ci	}
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	addr = its->vgic_its_base + offset;
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	len = region->access_flags & VGIC_ACCESS_64bit ? 8 : 4;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	if (is_write) {
20238c2ecf20Sopenharmony_ci		if (region->uaccess_its_write)
20248c2ecf20Sopenharmony_ci			ret = region->uaccess_its_write(dev->kvm, its, addr,
20258c2ecf20Sopenharmony_ci							len, *reg);
20268c2ecf20Sopenharmony_ci		else
20278c2ecf20Sopenharmony_ci			region->its_write(dev->kvm, its, addr, len, *reg);
20288c2ecf20Sopenharmony_ci	} else {
20298c2ecf20Sopenharmony_ci		*reg = region->its_read(dev->kvm, its, addr, len);
20308c2ecf20Sopenharmony_ci	}
20318c2ecf20Sopenharmony_ci	unlock_all_vcpus(dev->kvm);
20328c2ecf20Sopenharmony_ciout:
20338c2ecf20Sopenharmony_ci	mutex_unlock(&dev->kvm->lock);
20348c2ecf20Sopenharmony_ci	return ret;
20358c2ecf20Sopenharmony_ci}
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_cistatic u32 compute_next_devid_offset(struct list_head *h,
20388c2ecf20Sopenharmony_ci				     struct its_device *dev)
20398c2ecf20Sopenharmony_ci{
20408c2ecf20Sopenharmony_ci	struct its_device *next;
20418c2ecf20Sopenharmony_ci	u32 next_offset;
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	if (list_is_last(&dev->dev_list, h))
20448c2ecf20Sopenharmony_ci		return 0;
20458c2ecf20Sopenharmony_ci	next = list_next_entry(dev, dev_list);
20468c2ecf20Sopenharmony_ci	next_offset = next->device_id - dev->device_id;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
20498c2ecf20Sopenharmony_ci}
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_cistatic u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
20528c2ecf20Sopenharmony_ci{
20538c2ecf20Sopenharmony_ci	struct its_ite *next;
20548c2ecf20Sopenharmony_ci	u32 next_offset;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	if (list_is_last(&ite->ite_list, h))
20578c2ecf20Sopenharmony_ci		return 0;
20588c2ecf20Sopenharmony_ci	next = list_next_entry(ite, ite_list);
20598c2ecf20Sopenharmony_ci	next_offset = next->event_id - ite->event_id;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	return min_t(u32, next_offset, VITS_ITE_MAX_EVENTID_OFFSET);
20628c2ecf20Sopenharmony_ci}
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci/**
20658c2ecf20Sopenharmony_ci * entry_fn_t - Callback called on a table entry restore path
20668c2ecf20Sopenharmony_ci * @its: its handle
20678c2ecf20Sopenharmony_ci * @id: id of the entry
20688c2ecf20Sopenharmony_ci * @entry: pointer to the entry
20698c2ecf20Sopenharmony_ci * @opaque: pointer to an opaque data
20708c2ecf20Sopenharmony_ci *
20718c2ecf20Sopenharmony_ci * Return: < 0 on error, 0 if last element was identified, id offset to next
20728c2ecf20Sopenharmony_ci * element otherwise
20738c2ecf20Sopenharmony_ci */
20748c2ecf20Sopenharmony_citypedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
20758c2ecf20Sopenharmony_ci			  void *opaque);
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci/**
20788c2ecf20Sopenharmony_ci * scan_its_table - Scan a contiguous table in guest RAM and applies a function
20798c2ecf20Sopenharmony_ci * to each entry
20808c2ecf20Sopenharmony_ci *
20818c2ecf20Sopenharmony_ci * @its: its handle
20828c2ecf20Sopenharmony_ci * @base: base gpa of the table
20838c2ecf20Sopenharmony_ci * @size: size of the table in bytes
20848c2ecf20Sopenharmony_ci * @esz: entry size in bytes
20858c2ecf20Sopenharmony_ci * @start_id: the ID of the first entry in the table
20868c2ecf20Sopenharmony_ci * (non zero for 2d level tables)
20878c2ecf20Sopenharmony_ci * @fn: function to apply on each entry
20888c2ecf20Sopenharmony_ci *
20898c2ecf20Sopenharmony_ci * Return: < 0 on error, 0 if last element was identified, 1 otherwise
20908c2ecf20Sopenharmony_ci * (the last element may not be found on second level tables)
20918c2ecf20Sopenharmony_ci */
20928c2ecf20Sopenharmony_cistatic int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
20938c2ecf20Sopenharmony_ci			  int start_id, entry_fn_t fn, void *opaque)
20948c2ecf20Sopenharmony_ci{
20958c2ecf20Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
20968c2ecf20Sopenharmony_ci	unsigned long len = size;
20978c2ecf20Sopenharmony_ci	int id = start_id;
20988c2ecf20Sopenharmony_ci	gpa_t gpa = base;
20998c2ecf20Sopenharmony_ci	char entry[ESZ_MAX];
21008c2ecf20Sopenharmony_ci	int ret;
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	memset(entry, 0, esz);
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	while (true) {
21058c2ecf20Sopenharmony_ci		int next_offset;
21068c2ecf20Sopenharmony_ci		size_t byte_offset;
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci		ret = kvm_read_guest_lock(kvm, gpa, entry, esz);
21098c2ecf20Sopenharmony_ci		if (ret)
21108c2ecf20Sopenharmony_ci			return ret;
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci		next_offset = fn(its, id, entry, opaque);
21138c2ecf20Sopenharmony_ci		if (next_offset <= 0)
21148c2ecf20Sopenharmony_ci			return next_offset;
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci		byte_offset = next_offset * esz;
21178c2ecf20Sopenharmony_ci		if (byte_offset >= len)
21188c2ecf20Sopenharmony_ci			break;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci		id += next_offset;
21218c2ecf20Sopenharmony_ci		gpa += byte_offset;
21228c2ecf20Sopenharmony_ci		len -= byte_offset;
21238c2ecf20Sopenharmony_ci	}
21248c2ecf20Sopenharmony_ci	return 1;
21258c2ecf20Sopenharmony_ci}
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci/**
21288c2ecf20Sopenharmony_ci * vgic_its_save_ite - Save an interrupt translation entry at @gpa
21298c2ecf20Sopenharmony_ci */
21308c2ecf20Sopenharmony_cistatic int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
21318c2ecf20Sopenharmony_ci			      struct its_ite *ite, gpa_t gpa, int ite_esz)
21328c2ecf20Sopenharmony_ci{
21338c2ecf20Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
21348c2ecf20Sopenharmony_ci	u32 next_offset;
21358c2ecf20Sopenharmony_ci	u64 val;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
21388c2ecf20Sopenharmony_ci	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
21398c2ecf20Sopenharmony_ci	       ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
21408c2ecf20Sopenharmony_ci		ite->collection->collection_id;
21418c2ecf20Sopenharmony_ci	val = cpu_to_le64(val);
21428c2ecf20Sopenharmony_ci	return kvm_write_guest_lock(kvm, gpa, &val, ite_esz);
21438c2ecf20Sopenharmony_ci}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci/**
21468c2ecf20Sopenharmony_ci * vgic_its_restore_ite - restore an interrupt translation entry
21478c2ecf20Sopenharmony_ci * @event_id: id used for indexing
21488c2ecf20Sopenharmony_ci * @ptr: pointer to the ITE entry
21498c2ecf20Sopenharmony_ci * @opaque: pointer to the its_device
21508c2ecf20Sopenharmony_ci */
21518c2ecf20Sopenharmony_cistatic int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
21528c2ecf20Sopenharmony_ci				void *ptr, void *opaque)
21538c2ecf20Sopenharmony_ci{
21548c2ecf20Sopenharmony_ci	struct its_device *dev = (struct its_device *)opaque;
21558c2ecf20Sopenharmony_ci	struct its_collection *collection;
21568c2ecf20Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
21578c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu = NULL;
21588c2ecf20Sopenharmony_ci	u64 val;
21598c2ecf20Sopenharmony_ci	u64 *p = (u64 *)ptr;
21608c2ecf20Sopenharmony_ci	struct vgic_irq *irq;
21618c2ecf20Sopenharmony_ci	u32 coll_id, lpi_id;
21628c2ecf20Sopenharmony_ci	struct its_ite *ite;
21638c2ecf20Sopenharmony_ci	u32 offset;
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci	val = *p;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	val = le64_to_cpu(val);
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	coll_id = val & KVM_ITS_ITE_ICID_MASK;
21708c2ecf20Sopenharmony_ci	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	if (!lpi_id)
21738c2ecf20Sopenharmony_ci		return 1; /* invalid entry, no choice but to scan next entry */
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	if (lpi_id < VGIC_MIN_LPI)
21768c2ecf20Sopenharmony_ci		return -EINVAL;
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
21798c2ecf20Sopenharmony_ci	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
21808c2ecf20Sopenharmony_ci		return -EINVAL;
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	collection = find_collection(its, coll_id);
21838c2ecf20Sopenharmony_ci	if (!collection)
21848c2ecf20Sopenharmony_ci		return -EINVAL;
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	ite = vgic_its_alloc_ite(dev, collection, event_id);
21878c2ecf20Sopenharmony_ci	if (IS_ERR(ite))
21888c2ecf20Sopenharmony_ci		return PTR_ERR(ite);
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	if (its_is_collection_mapped(collection))
21918c2ecf20Sopenharmony_ci		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
21948c2ecf20Sopenharmony_ci	if (IS_ERR(irq))
21958c2ecf20Sopenharmony_ci		return PTR_ERR(irq);
21968c2ecf20Sopenharmony_ci	ite->irq = irq;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	return offset;
21998c2ecf20Sopenharmony_ci}
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_cistatic int vgic_its_ite_cmp(void *priv, const struct list_head *a,
22028c2ecf20Sopenharmony_ci			    const struct list_head *b)
22038c2ecf20Sopenharmony_ci{
22048c2ecf20Sopenharmony_ci	struct its_ite *itea = container_of(a, struct its_ite, ite_list);
22058c2ecf20Sopenharmony_ci	struct its_ite *iteb = container_of(b, struct its_ite, ite_list);
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	if (itea->event_id < iteb->event_id)
22088c2ecf20Sopenharmony_ci		return -1;
22098c2ecf20Sopenharmony_ci	else
22108c2ecf20Sopenharmony_ci		return 1;
22118c2ecf20Sopenharmony_ci}
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_cistatic int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
22148c2ecf20Sopenharmony_ci{
22158c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
22168c2ecf20Sopenharmony_ci	gpa_t base = device->itt_addr;
22178c2ecf20Sopenharmony_ci	struct its_ite *ite;
22188c2ecf20Sopenharmony_ci	int ret;
22198c2ecf20Sopenharmony_ci	int ite_esz = abi->ite_esz;
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	list_sort(NULL, &device->itt_head, vgic_its_ite_cmp);
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	list_for_each_entry(ite, &device->itt_head, ite_list) {
22248c2ecf20Sopenharmony_ci		gpa_t gpa = base + ite->event_id * ite_esz;
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci		/*
22278c2ecf20Sopenharmony_ci		 * If an LPI carries the HW bit, this means that this
22288c2ecf20Sopenharmony_ci		 * interrupt is controlled by GICv4, and we do not
22298c2ecf20Sopenharmony_ci		 * have direct access to that state. Let's simply fail
22308c2ecf20Sopenharmony_ci		 * the save operation...
22318c2ecf20Sopenharmony_ci		 */
22328c2ecf20Sopenharmony_ci		if (ite->irq->hw)
22338c2ecf20Sopenharmony_ci			return -EACCES;
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci		ret = vgic_its_save_ite(its, device, ite, gpa, ite_esz);
22368c2ecf20Sopenharmony_ci		if (ret)
22378c2ecf20Sopenharmony_ci			return ret;
22388c2ecf20Sopenharmony_ci	}
22398c2ecf20Sopenharmony_ci	return 0;
22408c2ecf20Sopenharmony_ci}
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci/**
22438c2ecf20Sopenharmony_ci * vgic_its_restore_itt - restore the ITT of a device
22448c2ecf20Sopenharmony_ci *
22458c2ecf20Sopenharmony_ci * @its: its handle
22468c2ecf20Sopenharmony_ci * @dev: device handle
22478c2ecf20Sopenharmony_ci *
22488c2ecf20Sopenharmony_ci * Return 0 on success, < 0 on error
22498c2ecf20Sopenharmony_ci */
22508c2ecf20Sopenharmony_cistatic int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
22518c2ecf20Sopenharmony_ci{
22528c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
22538c2ecf20Sopenharmony_ci	gpa_t base = dev->itt_addr;
22548c2ecf20Sopenharmony_ci	int ret;
22558c2ecf20Sopenharmony_ci	int ite_esz = abi->ite_esz;
22568c2ecf20Sopenharmony_ci	size_t max_size = BIT_ULL(dev->num_eventid_bits) * ite_esz;
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_ci	ret = scan_its_table(its, base, max_size, ite_esz, 0,
22598c2ecf20Sopenharmony_ci			     vgic_its_restore_ite, dev);
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci	/* scan_its_table returns +1 if all ITEs are invalid */
22628c2ecf20Sopenharmony_ci	if (ret > 0)
22638c2ecf20Sopenharmony_ci		ret = 0;
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci	return ret;
22668c2ecf20Sopenharmony_ci}
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci/**
22698c2ecf20Sopenharmony_ci * vgic_its_save_dte - Save a device table entry at a given GPA
22708c2ecf20Sopenharmony_ci *
22718c2ecf20Sopenharmony_ci * @its: ITS handle
22728c2ecf20Sopenharmony_ci * @dev: ITS device
22738c2ecf20Sopenharmony_ci * @ptr: GPA
22748c2ecf20Sopenharmony_ci */
22758c2ecf20Sopenharmony_cistatic int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
22768c2ecf20Sopenharmony_ci			     gpa_t ptr, int dte_esz)
22778c2ecf20Sopenharmony_ci{
22788c2ecf20Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
22798c2ecf20Sopenharmony_ci	u64 val, itt_addr_field;
22808c2ecf20Sopenharmony_ci	u32 next_offset;
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	itt_addr_field = dev->itt_addr >> 8;
22838c2ecf20Sopenharmony_ci	next_offset = compute_next_devid_offset(&its->device_list, dev);
22848c2ecf20Sopenharmony_ci	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
22858c2ecf20Sopenharmony_ci	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
22868c2ecf20Sopenharmony_ci	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
22878c2ecf20Sopenharmony_ci		(dev->num_eventid_bits - 1));
22888c2ecf20Sopenharmony_ci	val = cpu_to_le64(val);
22898c2ecf20Sopenharmony_ci	return kvm_write_guest_lock(kvm, ptr, &val, dte_esz);
22908c2ecf20Sopenharmony_ci}
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_ci/**
22938c2ecf20Sopenharmony_ci * vgic_its_restore_dte - restore a device table entry
22948c2ecf20Sopenharmony_ci *
22958c2ecf20Sopenharmony_ci * @its: its handle
22968c2ecf20Sopenharmony_ci * @id: device id the DTE corresponds to
22978c2ecf20Sopenharmony_ci * @ptr: kernel VA where the 8 byte DTE is located
22988c2ecf20Sopenharmony_ci * @opaque: unused
22998c2ecf20Sopenharmony_ci *
23008c2ecf20Sopenharmony_ci * Return: < 0 on error, 0 if the dte is the last one, id offset to the
23018c2ecf20Sopenharmony_ci * next dte otherwise
23028c2ecf20Sopenharmony_ci */
23038c2ecf20Sopenharmony_cistatic int vgic_its_restore_dte(struct vgic_its *its, u32 id,
23048c2ecf20Sopenharmony_ci				void *ptr, void *opaque)
23058c2ecf20Sopenharmony_ci{
23068c2ecf20Sopenharmony_ci	struct its_device *dev;
23078c2ecf20Sopenharmony_ci	gpa_t itt_addr;
23088c2ecf20Sopenharmony_ci	u8 num_eventid_bits;
23098c2ecf20Sopenharmony_ci	u64 entry = *(u64 *)ptr;
23108c2ecf20Sopenharmony_ci	bool valid;
23118c2ecf20Sopenharmony_ci	u32 offset;
23128c2ecf20Sopenharmony_ci	int ret;
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	entry = le64_to_cpu(entry);
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
23178c2ecf20Sopenharmony_ci	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
23188c2ecf20Sopenharmony_ci	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
23198c2ecf20Sopenharmony_ci			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	if (!valid)
23228c2ecf20Sopenharmony_ci		return 1;
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci	/* dte entry is valid */
23258c2ecf20Sopenharmony_ci	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
23288c2ecf20Sopenharmony_ci	if (IS_ERR(dev))
23298c2ecf20Sopenharmony_ci		return PTR_ERR(dev);
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci	ret = vgic_its_restore_itt(its, dev);
23328c2ecf20Sopenharmony_ci	if (ret) {
23338c2ecf20Sopenharmony_ci		vgic_its_free_device(its->dev->kvm, dev);
23348c2ecf20Sopenharmony_ci		return ret;
23358c2ecf20Sopenharmony_ci	}
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	return offset;
23388c2ecf20Sopenharmony_ci}
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_cistatic int vgic_its_device_cmp(void *priv, const struct list_head *a,
23418c2ecf20Sopenharmony_ci			       const struct list_head *b)
23428c2ecf20Sopenharmony_ci{
23438c2ecf20Sopenharmony_ci	struct its_device *deva = container_of(a, struct its_device, dev_list);
23448c2ecf20Sopenharmony_ci	struct its_device *devb = container_of(b, struct its_device, dev_list);
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	if (deva->device_id < devb->device_id)
23478c2ecf20Sopenharmony_ci		return -1;
23488c2ecf20Sopenharmony_ci	else
23498c2ecf20Sopenharmony_ci		return 1;
23508c2ecf20Sopenharmony_ci}
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ci/**
23538c2ecf20Sopenharmony_ci * vgic_its_save_device_tables - Save the device table and all ITT
23548c2ecf20Sopenharmony_ci * into guest RAM
23558c2ecf20Sopenharmony_ci *
23568c2ecf20Sopenharmony_ci * L1/L2 handling is hidden by vgic_its_check_id() helper which directly
23578c2ecf20Sopenharmony_ci * returns the GPA of the device entry
23588c2ecf20Sopenharmony_ci */
23598c2ecf20Sopenharmony_cistatic int vgic_its_save_device_tables(struct vgic_its *its)
23608c2ecf20Sopenharmony_ci{
23618c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
23628c2ecf20Sopenharmony_ci	u64 baser = its->baser_device_table;
23638c2ecf20Sopenharmony_ci	struct its_device *dev;
23648c2ecf20Sopenharmony_ci	int dte_esz = abi->dte_esz;
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	if (!(baser & GITS_BASER_VALID))
23678c2ecf20Sopenharmony_ci		return 0;
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	list_sort(NULL, &its->device_list, vgic_its_device_cmp);
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &its->device_list, dev_list) {
23728c2ecf20Sopenharmony_ci		int ret;
23738c2ecf20Sopenharmony_ci		gpa_t eaddr;
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci		if (!vgic_its_check_id(its, baser,
23768c2ecf20Sopenharmony_ci				       dev->device_id, &eaddr))
23778c2ecf20Sopenharmony_ci			return -EINVAL;
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci		ret = vgic_its_save_itt(its, dev);
23808c2ecf20Sopenharmony_ci		if (ret)
23818c2ecf20Sopenharmony_ci			return ret;
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci		ret = vgic_its_save_dte(its, dev, eaddr, dte_esz);
23848c2ecf20Sopenharmony_ci		if (ret)
23858c2ecf20Sopenharmony_ci			return ret;
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ci	return 0;
23888c2ecf20Sopenharmony_ci}
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci/**
23918c2ecf20Sopenharmony_ci * handle_l1_dte - callback used for L1 device table entries (2 stage case)
23928c2ecf20Sopenharmony_ci *
23938c2ecf20Sopenharmony_ci * @its: its handle
23948c2ecf20Sopenharmony_ci * @id: index of the entry in the L1 table
23958c2ecf20Sopenharmony_ci * @addr: kernel VA
23968c2ecf20Sopenharmony_ci * @opaque: unused
23978c2ecf20Sopenharmony_ci *
23988c2ecf20Sopenharmony_ci * L1 table entries are scanned by steps of 1 entry
23998c2ecf20Sopenharmony_ci * Return < 0 if error, 0 if last dte was found when scanning the L2
24008c2ecf20Sopenharmony_ci * table, +1 otherwise (meaning next L1 entry must be scanned)
24018c2ecf20Sopenharmony_ci */
24028c2ecf20Sopenharmony_cistatic int handle_l1_dte(struct vgic_its *its, u32 id, void *addr,
24038c2ecf20Sopenharmony_ci			 void *opaque)
24048c2ecf20Sopenharmony_ci{
24058c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
24068c2ecf20Sopenharmony_ci	int l2_start_id = id * (SZ_64K / abi->dte_esz);
24078c2ecf20Sopenharmony_ci	u64 entry = *(u64 *)addr;
24088c2ecf20Sopenharmony_ci	int dte_esz = abi->dte_esz;
24098c2ecf20Sopenharmony_ci	gpa_t gpa;
24108c2ecf20Sopenharmony_ci	int ret;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	entry = le64_to_cpu(entry);
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	if (!(entry & KVM_ITS_L1E_VALID_MASK))
24158c2ecf20Sopenharmony_ci		return 1;
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	gpa = entry & KVM_ITS_L1E_ADDR_MASK;
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci	ret = scan_its_table(its, gpa, SZ_64K, dte_esz,
24208c2ecf20Sopenharmony_ci			     l2_start_id, vgic_its_restore_dte, NULL);
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	return ret;
24238c2ecf20Sopenharmony_ci}
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci/**
24268c2ecf20Sopenharmony_ci * vgic_its_restore_device_tables - Restore the device table and all ITT
24278c2ecf20Sopenharmony_ci * from guest RAM to internal data structs
24288c2ecf20Sopenharmony_ci */
24298c2ecf20Sopenharmony_cistatic int vgic_its_restore_device_tables(struct vgic_its *its)
24308c2ecf20Sopenharmony_ci{
24318c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
24328c2ecf20Sopenharmony_ci	u64 baser = its->baser_device_table;
24338c2ecf20Sopenharmony_ci	int l1_esz, ret;
24348c2ecf20Sopenharmony_ci	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
24358c2ecf20Sopenharmony_ci	gpa_t l1_gpa;
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	if (!(baser & GITS_BASER_VALID))
24388c2ecf20Sopenharmony_ci		return 0;
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci	l1_gpa = GITS_BASER_ADDR_48_to_52(baser);
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	if (baser & GITS_BASER_INDIRECT) {
24438c2ecf20Sopenharmony_ci		l1_esz = GITS_LVL1_ENTRY_SIZE;
24448c2ecf20Sopenharmony_ci		ret = scan_its_table(its, l1_gpa, l1_tbl_size, l1_esz, 0,
24458c2ecf20Sopenharmony_ci				     handle_l1_dte, NULL);
24468c2ecf20Sopenharmony_ci	} else {
24478c2ecf20Sopenharmony_ci		l1_esz = abi->dte_esz;
24488c2ecf20Sopenharmony_ci		ret = scan_its_table(its, l1_gpa, l1_tbl_size, l1_esz, 0,
24498c2ecf20Sopenharmony_ci				     vgic_its_restore_dte, NULL);
24508c2ecf20Sopenharmony_ci	}
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	/* scan_its_table returns +1 if all entries are invalid */
24538c2ecf20Sopenharmony_ci	if (ret > 0)
24548c2ecf20Sopenharmony_ci		ret = 0;
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	return ret;
24578c2ecf20Sopenharmony_ci}
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_cistatic int vgic_its_save_cte(struct vgic_its *its,
24608c2ecf20Sopenharmony_ci			     struct its_collection *collection,
24618c2ecf20Sopenharmony_ci			     gpa_t gpa, int esz)
24628c2ecf20Sopenharmony_ci{
24638c2ecf20Sopenharmony_ci	u64 val;
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	val = (1ULL << KVM_ITS_CTE_VALID_SHIFT |
24668c2ecf20Sopenharmony_ci	       ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
24678c2ecf20Sopenharmony_ci	       collection->collection_id);
24688c2ecf20Sopenharmony_ci	val = cpu_to_le64(val);
24698c2ecf20Sopenharmony_ci	return kvm_write_guest_lock(its->dev->kvm, gpa, &val, esz);
24708c2ecf20Sopenharmony_ci}
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_cistatic int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
24738c2ecf20Sopenharmony_ci{
24748c2ecf20Sopenharmony_ci	struct its_collection *collection;
24758c2ecf20Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
24768c2ecf20Sopenharmony_ci	u32 target_addr, coll_id;
24778c2ecf20Sopenharmony_ci	u64 val;
24788c2ecf20Sopenharmony_ci	int ret;
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci	BUG_ON(esz > sizeof(val));
24818c2ecf20Sopenharmony_ci	ret = kvm_read_guest_lock(kvm, gpa, &val, esz);
24828c2ecf20Sopenharmony_ci	if (ret)
24838c2ecf20Sopenharmony_ci		return ret;
24848c2ecf20Sopenharmony_ci	val = le64_to_cpu(val);
24858c2ecf20Sopenharmony_ci	if (!(val & KVM_ITS_CTE_VALID_MASK))
24868c2ecf20Sopenharmony_ci		return 0;
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	target_addr = (u32)(val >> KVM_ITS_CTE_RDBASE_SHIFT);
24898c2ecf20Sopenharmony_ci	coll_id = val & KVM_ITS_CTE_ICID_MASK;
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	if (target_addr != COLLECTION_NOT_MAPPED &&
24928c2ecf20Sopenharmony_ci	    target_addr >= atomic_read(&kvm->online_vcpus))
24938c2ecf20Sopenharmony_ci		return -EINVAL;
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci	collection = find_collection(its, coll_id);
24968c2ecf20Sopenharmony_ci	if (collection)
24978c2ecf20Sopenharmony_ci		return -EEXIST;
24988c2ecf20Sopenharmony_ci	ret = vgic_its_alloc_collection(its, &collection, coll_id);
24998c2ecf20Sopenharmony_ci	if (ret)
25008c2ecf20Sopenharmony_ci		return ret;
25018c2ecf20Sopenharmony_ci	collection->target_addr = target_addr;
25028c2ecf20Sopenharmony_ci	return 1;
25038c2ecf20Sopenharmony_ci}
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci/**
25068c2ecf20Sopenharmony_ci * vgic_its_save_collection_table - Save the collection table into
25078c2ecf20Sopenharmony_ci * guest RAM
25088c2ecf20Sopenharmony_ci */
25098c2ecf20Sopenharmony_cistatic int vgic_its_save_collection_table(struct vgic_its *its)
25108c2ecf20Sopenharmony_ci{
25118c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
25128c2ecf20Sopenharmony_ci	u64 baser = its->baser_coll_table;
25138c2ecf20Sopenharmony_ci	gpa_t gpa = GITS_BASER_ADDR_48_to_52(baser);
25148c2ecf20Sopenharmony_ci	struct its_collection *collection;
25158c2ecf20Sopenharmony_ci	u64 val;
25168c2ecf20Sopenharmony_ci	size_t max_size, filled = 0;
25178c2ecf20Sopenharmony_ci	int ret, cte_esz = abi->cte_esz;
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	if (!(baser & GITS_BASER_VALID))
25208c2ecf20Sopenharmony_ci		return 0;
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci	list_for_each_entry(collection, &its->collection_list, coll_list) {
25258c2ecf20Sopenharmony_ci		ret = vgic_its_save_cte(its, collection, gpa, cte_esz);
25268c2ecf20Sopenharmony_ci		if (ret)
25278c2ecf20Sopenharmony_ci			return ret;
25288c2ecf20Sopenharmony_ci		gpa += cte_esz;
25298c2ecf20Sopenharmony_ci		filled += cte_esz;
25308c2ecf20Sopenharmony_ci	}
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci	if (filled == max_size)
25338c2ecf20Sopenharmony_ci		return 0;
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci	/*
25368c2ecf20Sopenharmony_ci	 * table is not fully filled, add a last dummy element
25378c2ecf20Sopenharmony_ci	 * with valid bit unset
25388c2ecf20Sopenharmony_ci	 */
25398c2ecf20Sopenharmony_ci	val = 0;
25408c2ecf20Sopenharmony_ci	BUG_ON(cte_esz > sizeof(val));
25418c2ecf20Sopenharmony_ci	ret = kvm_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz);
25428c2ecf20Sopenharmony_ci	return ret;
25438c2ecf20Sopenharmony_ci}
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci/**
25468c2ecf20Sopenharmony_ci * vgic_its_restore_collection_table - reads the collection table
25478c2ecf20Sopenharmony_ci * in guest memory and restores the ITS internal state. Requires the
25488c2ecf20Sopenharmony_ci * BASER registers to be restored before.
25498c2ecf20Sopenharmony_ci */
25508c2ecf20Sopenharmony_cistatic int vgic_its_restore_collection_table(struct vgic_its *its)
25518c2ecf20Sopenharmony_ci{
25528c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
25538c2ecf20Sopenharmony_ci	u64 baser = its->baser_coll_table;
25548c2ecf20Sopenharmony_ci	int cte_esz = abi->cte_esz;
25558c2ecf20Sopenharmony_ci	size_t max_size, read = 0;
25568c2ecf20Sopenharmony_ci	gpa_t gpa;
25578c2ecf20Sopenharmony_ci	int ret;
25588c2ecf20Sopenharmony_ci
25598c2ecf20Sopenharmony_ci	if (!(baser & GITS_BASER_VALID))
25608c2ecf20Sopenharmony_ci		return 0;
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	gpa = GITS_BASER_ADDR_48_to_52(baser);
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci	max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci	while (read < max_size) {
25678c2ecf20Sopenharmony_ci		ret = vgic_its_restore_cte(its, gpa, cte_esz);
25688c2ecf20Sopenharmony_ci		if (ret <= 0)
25698c2ecf20Sopenharmony_ci			break;
25708c2ecf20Sopenharmony_ci		gpa += cte_esz;
25718c2ecf20Sopenharmony_ci		read += cte_esz;
25728c2ecf20Sopenharmony_ci	}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	if (ret > 0)
25758c2ecf20Sopenharmony_ci		return 0;
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci	return ret;
25788c2ecf20Sopenharmony_ci}
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci/**
25818c2ecf20Sopenharmony_ci * vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
25828c2ecf20Sopenharmony_ci * according to v0 ABI
25838c2ecf20Sopenharmony_ci */
25848c2ecf20Sopenharmony_cistatic int vgic_its_save_tables_v0(struct vgic_its *its)
25858c2ecf20Sopenharmony_ci{
25868c2ecf20Sopenharmony_ci	int ret;
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	ret = vgic_its_save_device_tables(its);
25898c2ecf20Sopenharmony_ci	if (ret)
25908c2ecf20Sopenharmony_ci		return ret;
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci	return vgic_its_save_collection_table(its);
25938c2ecf20Sopenharmony_ci}
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci/**
25968c2ecf20Sopenharmony_ci * vgic_its_restore_tables_v0 - Restore the ITS tables from guest RAM
25978c2ecf20Sopenharmony_ci * to internal data structs according to V0 ABI
25988c2ecf20Sopenharmony_ci *
25998c2ecf20Sopenharmony_ci */
26008c2ecf20Sopenharmony_cistatic int vgic_its_restore_tables_v0(struct vgic_its *its)
26018c2ecf20Sopenharmony_ci{
26028c2ecf20Sopenharmony_ci	int ret;
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci	ret = vgic_its_restore_collection_table(its);
26058c2ecf20Sopenharmony_ci	if (ret)
26068c2ecf20Sopenharmony_ci		return ret;
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	return vgic_its_restore_device_tables(its);
26098c2ecf20Sopenharmony_ci}
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_cistatic int vgic_its_commit_v0(struct vgic_its *its)
26128c2ecf20Sopenharmony_ci{
26138c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi;
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	abi = vgic_its_get_abi(its);
26168c2ecf20Sopenharmony_ci	its->baser_coll_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
26178c2ecf20Sopenharmony_ci	its->baser_device_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci	its->baser_coll_table |= (GIC_ENCODE_SZ(abi->cte_esz, 5)
26208c2ecf20Sopenharmony_ci					<< GITS_BASER_ENTRY_SIZE_SHIFT);
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	its->baser_device_table |= (GIC_ENCODE_SZ(abi->dte_esz, 5)
26238c2ecf20Sopenharmony_ci					<< GITS_BASER_ENTRY_SIZE_SHIFT);
26248c2ecf20Sopenharmony_ci	return 0;
26258c2ecf20Sopenharmony_ci}
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_cistatic void vgic_its_reset(struct kvm *kvm, struct vgic_its *its)
26288c2ecf20Sopenharmony_ci{
26298c2ecf20Sopenharmony_ci	/* We need to keep the ABI specific field values */
26308c2ecf20Sopenharmony_ci	its->baser_coll_table &= ~GITS_BASER_VALID;
26318c2ecf20Sopenharmony_ci	its->baser_device_table &= ~GITS_BASER_VALID;
26328c2ecf20Sopenharmony_ci	its->cbaser = 0;
26338c2ecf20Sopenharmony_ci	its->creadr = 0;
26348c2ecf20Sopenharmony_ci	its->cwriter = 0;
26358c2ecf20Sopenharmony_ci	its->enabled = 0;
26368c2ecf20Sopenharmony_ci	vgic_its_free_device_list(kvm, its);
26378c2ecf20Sopenharmony_ci	vgic_its_free_collection_list(kvm, its);
26388c2ecf20Sopenharmony_ci}
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_cistatic int vgic_its_has_attr(struct kvm_device *dev,
26418c2ecf20Sopenharmony_ci			     struct kvm_device_attr *attr)
26428c2ecf20Sopenharmony_ci{
26438c2ecf20Sopenharmony_ci	switch (attr->group) {
26448c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ADDR:
26458c2ecf20Sopenharmony_ci		switch (attr->attr) {
26468c2ecf20Sopenharmony_ci		case KVM_VGIC_ITS_ADDR_TYPE:
26478c2ecf20Sopenharmony_ci			return 0;
26488c2ecf20Sopenharmony_ci		}
26498c2ecf20Sopenharmony_ci		break;
26508c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_CTRL:
26518c2ecf20Sopenharmony_ci		switch (attr->attr) {
26528c2ecf20Sopenharmony_ci		case KVM_DEV_ARM_VGIC_CTRL_INIT:
26538c2ecf20Sopenharmony_ci			return 0;
26548c2ecf20Sopenharmony_ci		case KVM_DEV_ARM_ITS_CTRL_RESET:
26558c2ecf20Sopenharmony_ci			return 0;
26568c2ecf20Sopenharmony_ci		case KVM_DEV_ARM_ITS_SAVE_TABLES:
26578c2ecf20Sopenharmony_ci			return 0;
26588c2ecf20Sopenharmony_ci		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
26598c2ecf20Sopenharmony_ci			return 0;
26608c2ecf20Sopenharmony_ci		}
26618c2ecf20Sopenharmony_ci		break;
26628c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS:
26638c2ecf20Sopenharmony_ci		return vgic_its_has_attr_regs(dev, attr);
26648c2ecf20Sopenharmony_ci	}
26658c2ecf20Sopenharmony_ci	return -ENXIO;
26668c2ecf20Sopenharmony_ci}
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_cistatic int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
26698c2ecf20Sopenharmony_ci{
26708c2ecf20Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
26718c2ecf20Sopenharmony_ci	int ret = 0;
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	if (attr == KVM_DEV_ARM_VGIC_CTRL_INIT) /* Nothing to do */
26748c2ecf20Sopenharmony_ci		return 0;
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	mutex_lock(&kvm->lock);
26778c2ecf20Sopenharmony_ci	mutex_lock(&its->its_lock);
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci	if (!lock_all_vcpus(kvm)) {
26808c2ecf20Sopenharmony_ci		mutex_unlock(&its->its_lock);
26818c2ecf20Sopenharmony_ci		mutex_unlock(&kvm->lock);
26828c2ecf20Sopenharmony_ci		return -EBUSY;
26838c2ecf20Sopenharmony_ci	}
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci	switch (attr) {
26868c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_ITS_CTRL_RESET:
26878c2ecf20Sopenharmony_ci		vgic_its_reset(kvm, its);
26888c2ecf20Sopenharmony_ci		break;
26898c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_ITS_SAVE_TABLES:
26908c2ecf20Sopenharmony_ci		ret = abi->save_tables(its);
26918c2ecf20Sopenharmony_ci		break;
26928c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_ITS_RESTORE_TABLES:
26938c2ecf20Sopenharmony_ci		ret = abi->restore_tables(its);
26948c2ecf20Sopenharmony_ci		break;
26958c2ecf20Sopenharmony_ci	}
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	unlock_all_vcpus(kvm);
26988c2ecf20Sopenharmony_ci	mutex_unlock(&its->its_lock);
26998c2ecf20Sopenharmony_ci	mutex_unlock(&kvm->lock);
27008c2ecf20Sopenharmony_ci	return ret;
27018c2ecf20Sopenharmony_ci}
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_cistatic int vgic_its_set_attr(struct kvm_device *dev,
27048c2ecf20Sopenharmony_ci			     struct kvm_device_attr *attr)
27058c2ecf20Sopenharmony_ci{
27068c2ecf20Sopenharmony_ci	struct vgic_its *its = dev->private;
27078c2ecf20Sopenharmony_ci	int ret;
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	switch (attr->group) {
27108c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
27118c2ecf20Sopenharmony_ci		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
27128c2ecf20Sopenharmony_ci		unsigned long type = (unsigned long)attr->attr;
27138c2ecf20Sopenharmony_ci		u64 addr;
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci		if (type != KVM_VGIC_ITS_ADDR_TYPE)
27168c2ecf20Sopenharmony_ci			return -ENODEV;
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci		if (copy_from_user(&addr, uaddr, sizeof(addr)))
27198c2ecf20Sopenharmony_ci			return -EFAULT;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci		ret = vgic_check_ioaddr(dev->kvm, &its->vgic_its_base,
27228c2ecf20Sopenharmony_ci					addr, SZ_64K);
27238c2ecf20Sopenharmony_ci		if (ret)
27248c2ecf20Sopenharmony_ci			return ret;
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci		return vgic_register_its_iodev(dev->kvm, its, addr);
27278c2ecf20Sopenharmony_ci	}
27288c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_CTRL:
27298c2ecf20Sopenharmony_ci		return vgic_its_ctrl(dev->kvm, its, attr->attr);
27308c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
27318c2ecf20Sopenharmony_ci		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
27328c2ecf20Sopenharmony_ci		u64 reg;
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci		if (get_user(reg, uaddr))
27358c2ecf20Sopenharmony_ci			return -EFAULT;
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci		return vgic_its_attr_regs_access(dev, attr, &reg, true);
27388c2ecf20Sopenharmony_ci	}
27398c2ecf20Sopenharmony_ci	}
27408c2ecf20Sopenharmony_ci	return -ENXIO;
27418c2ecf20Sopenharmony_ci}
27428c2ecf20Sopenharmony_ci
27438c2ecf20Sopenharmony_cistatic int vgic_its_get_attr(struct kvm_device *dev,
27448c2ecf20Sopenharmony_ci			     struct kvm_device_attr *attr)
27458c2ecf20Sopenharmony_ci{
27468c2ecf20Sopenharmony_ci	switch (attr->group) {
27478c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
27488c2ecf20Sopenharmony_ci		struct vgic_its *its = dev->private;
27498c2ecf20Sopenharmony_ci		u64 addr = its->vgic_its_base;
27508c2ecf20Sopenharmony_ci		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
27518c2ecf20Sopenharmony_ci		unsigned long type = (unsigned long)attr->attr;
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci		if (type != KVM_VGIC_ITS_ADDR_TYPE)
27548c2ecf20Sopenharmony_ci			return -ENODEV;
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci		if (copy_to_user(uaddr, &addr, sizeof(addr)))
27578c2ecf20Sopenharmony_ci			return -EFAULT;
27588c2ecf20Sopenharmony_ci		break;
27598c2ecf20Sopenharmony_ci	}
27608c2ecf20Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
27618c2ecf20Sopenharmony_ci		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
27628c2ecf20Sopenharmony_ci		u64 reg;
27638c2ecf20Sopenharmony_ci		int ret;
27648c2ecf20Sopenharmony_ci
27658c2ecf20Sopenharmony_ci		ret = vgic_its_attr_regs_access(dev, attr, &reg, false);
27668c2ecf20Sopenharmony_ci		if (ret)
27678c2ecf20Sopenharmony_ci			return ret;
27688c2ecf20Sopenharmony_ci		return put_user(reg, uaddr);
27698c2ecf20Sopenharmony_ci	}
27708c2ecf20Sopenharmony_ci	default:
27718c2ecf20Sopenharmony_ci		return -ENXIO;
27728c2ecf20Sopenharmony_ci	}
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_ci	return 0;
27758c2ecf20Sopenharmony_ci}
27768c2ecf20Sopenharmony_ci
27778c2ecf20Sopenharmony_cistatic struct kvm_device_ops kvm_arm_vgic_its_ops = {
27788c2ecf20Sopenharmony_ci	.name = "kvm-arm-vgic-its",
27798c2ecf20Sopenharmony_ci	.create = vgic_its_create,
27808c2ecf20Sopenharmony_ci	.destroy = vgic_its_destroy,
27818c2ecf20Sopenharmony_ci	.set_attr = vgic_its_set_attr,
27828c2ecf20Sopenharmony_ci	.get_attr = vgic_its_get_attr,
27838c2ecf20Sopenharmony_ci	.has_attr = vgic_its_has_attr,
27848c2ecf20Sopenharmony_ci};
27858c2ecf20Sopenharmony_ci
27868c2ecf20Sopenharmony_ciint kvm_vgic_register_its_device(void)
27878c2ecf20Sopenharmony_ci{
27888c2ecf20Sopenharmony_ci	return kvm_register_device_ops(&kvm_arm_vgic_its_ops,
27898c2ecf20Sopenharmony_ci				       KVM_DEV_TYPE_ARM_VGIC_ITS);
27908c2ecf20Sopenharmony_ci}
2791