162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * GICv3 ITS emulation
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2015,2016 ARM Ltd.
662306a36Sopenharmony_ci * Author: Andre Przywara <andre.przywara@arm.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/cpu.h>
1062306a36Sopenharmony_ci#include <linux/kvm.h>
1162306a36Sopenharmony_ci#include <linux/kvm_host.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/list.h>
1462306a36Sopenharmony_ci#include <linux/uaccess.h>
1562306a36Sopenharmony_ci#include <linux/list_sort.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/irqchip/arm-gic-v3.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <asm/kvm_emulate.h>
2062306a36Sopenharmony_ci#include <asm/kvm_arm.h>
2162306a36Sopenharmony_ci#include <asm/kvm_mmu.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "vgic.h"
2462306a36Sopenharmony_ci#include "vgic-mmio.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int vgic_its_save_tables_v0(struct vgic_its *its);
2762306a36Sopenharmony_cistatic int vgic_its_restore_tables_v0(struct vgic_its *its);
2862306a36Sopenharmony_cistatic int vgic_its_commit_v0(struct vgic_its *its);
2962306a36Sopenharmony_cistatic int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
3062306a36Sopenharmony_ci			     struct kvm_vcpu *filter_vcpu, bool needs_inv);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * Creates a new (reference to a) struct vgic_irq for a given LPI.
3462306a36Sopenharmony_ci * If this LPI is already mapped on another ITS, we increase its refcount
3562306a36Sopenharmony_ci * and return a pointer to the existing structure.
3662306a36Sopenharmony_ci * If this is a "new" LPI, we allocate and initialize a new struct vgic_irq.
3762306a36Sopenharmony_ci * This function returns a pointer to the _unlocked_ structure.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistatic struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
4062306a36Sopenharmony_ci				     struct kvm_vcpu *vcpu)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
4362306a36Sopenharmony_ci	struct vgic_irq *irq = vgic_get_irq(kvm, NULL, intid), *oldirq;
4462306a36Sopenharmony_ci	unsigned long flags;
4562306a36Sopenharmony_ci	int ret;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* In this case there is no put, since we keep the reference. */
4862306a36Sopenharmony_ci	if (irq)
4962306a36Sopenharmony_ci		return irq;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	irq = kzalloc(sizeof(struct vgic_irq), GFP_KERNEL_ACCOUNT);
5262306a36Sopenharmony_ci	if (!irq)
5362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	INIT_LIST_HEAD(&irq->lpi_list);
5662306a36Sopenharmony_ci	INIT_LIST_HEAD(&irq->ap_list);
5762306a36Sopenharmony_ci	raw_spin_lock_init(&irq->irq_lock);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	irq->config = VGIC_CONFIG_EDGE;
6062306a36Sopenharmony_ci	kref_init(&irq->refcount);
6162306a36Sopenharmony_ci	irq->intid = intid;
6262306a36Sopenharmony_ci	irq->target_vcpu = vcpu;
6362306a36Sopenharmony_ci	irq->group = 1;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/*
6862306a36Sopenharmony_ci	 * There could be a race with another vgic_add_lpi(), so we need to
6962306a36Sopenharmony_ci	 * check that we don't add a second list entry with the same LPI.
7062306a36Sopenharmony_ci	 */
7162306a36Sopenharmony_ci	list_for_each_entry(oldirq, &dist->lpi_list_head, lpi_list) {
7262306a36Sopenharmony_ci		if (oldirq->intid != intid)
7362306a36Sopenharmony_ci			continue;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		/* Someone was faster with adding this LPI, lets use that. */
7662306a36Sopenharmony_ci		kfree(irq);
7762306a36Sopenharmony_ci		irq = oldirq;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		/*
8062306a36Sopenharmony_ci		 * This increases the refcount, the caller is expected to
8162306a36Sopenharmony_ci		 * call vgic_put_irq() on the returned pointer once it's
8262306a36Sopenharmony_ci		 * finished with the IRQ.
8362306a36Sopenharmony_ci		 */
8462306a36Sopenharmony_ci		vgic_get_irq_kref(irq);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		goto out_unlock;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	list_add_tail(&irq->lpi_list, &dist->lpi_list_head);
9062306a36Sopenharmony_ci	dist->lpi_list_count++;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciout_unlock:
9362306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/*
9662306a36Sopenharmony_ci	 * We "cache" the configuration table entries in our struct vgic_irq's.
9762306a36Sopenharmony_ci	 * However we only have those structs for mapped IRQs, so we read in
9862306a36Sopenharmony_ci	 * the respective config data from memory here upon mapping the LPI.
9962306a36Sopenharmony_ci	 *
10062306a36Sopenharmony_ci	 * Should any of these fail, behave as if we couldn't create the LPI
10162306a36Sopenharmony_ci	 * by dropping the refcount and returning the error.
10262306a36Sopenharmony_ci	 */
10362306a36Sopenharmony_ci	ret = update_lpi_config(kvm, irq, NULL, false);
10462306a36Sopenharmony_ci	if (ret) {
10562306a36Sopenharmony_ci		vgic_put_irq(kvm, irq);
10662306a36Sopenharmony_ci		return ERR_PTR(ret);
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	ret = vgic_v3_lpi_sync_pending_status(kvm, irq);
11062306a36Sopenharmony_ci	if (ret) {
11162306a36Sopenharmony_ci		vgic_put_irq(kvm, irq);
11262306a36Sopenharmony_ci		return ERR_PTR(ret);
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return irq;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistruct its_device {
11962306a36Sopenharmony_ci	struct list_head dev_list;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/* the head for the list of ITTEs */
12262306a36Sopenharmony_ci	struct list_head itt_head;
12362306a36Sopenharmony_ci	u32 num_eventid_bits;
12462306a36Sopenharmony_ci	gpa_t itt_addr;
12562306a36Sopenharmony_ci	u32 device_id;
12662306a36Sopenharmony_ci};
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define COLLECTION_NOT_MAPPED ((u32)~0)
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistruct its_collection {
13162306a36Sopenharmony_ci	struct list_head coll_list;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	u32 collection_id;
13462306a36Sopenharmony_ci	u32 target_addr;
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#define its_is_collection_mapped(coll) ((coll) && \
13862306a36Sopenharmony_ci				((coll)->target_addr != COLLECTION_NOT_MAPPED))
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct its_ite {
14162306a36Sopenharmony_ci	struct list_head ite_list;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	struct vgic_irq *irq;
14462306a36Sopenharmony_ci	struct its_collection *collection;
14562306a36Sopenharmony_ci	u32 event_id;
14662306a36Sopenharmony_ci};
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistruct vgic_translation_cache_entry {
14962306a36Sopenharmony_ci	struct list_head	entry;
15062306a36Sopenharmony_ci	phys_addr_t		db;
15162306a36Sopenharmony_ci	u32			devid;
15262306a36Sopenharmony_ci	u32			eventid;
15362306a36Sopenharmony_ci	struct vgic_irq		*irq;
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/**
15762306a36Sopenharmony_ci * struct vgic_its_abi - ITS abi ops and settings
15862306a36Sopenharmony_ci * @cte_esz: collection table entry size
15962306a36Sopenharmony_ci * @dte_esz: device table entry size
16062306a36Sopenharmony_ci * @ite_esz: interrupt translation table entry size
16162306a36Sopenharmony_ci * @save tables: save the ITS tables into guest RAM
16262306a36Sopenharmony_ci * @restore_tables: restore the ITS internal structs from tables
16362306a36Sopenharmony_ci *  stored in guest RAM
16462306a36Sopenharmony_ci * @commit: initialize the registers which expose the ABI settings,
16562306a36Sopenharmony_ci *  especially the entry sizes
16662306a36Sopenharmony_ci */
16762306a36Sopenharmony_cistruct vgic_its_abi {
16862306a36Sopenharmony_ci	int cte_esz;
16962306a36Sopenharmony_ci	int dte_esz;
17062306a36Sopenharmony_ci	int ite_esz;
17162306a36Sopenharmony_ci	int (*save_tables)(struct vgic_its *its);
17262306a36Sopenharmony_ci	int (*restore_tables)(struct vgic_its *its);
17362306a36Sopenharmony_ci	int (*commit)(struct vgic_its *its);
17462306a36Sopenharmony_ci};
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci#define ABI_0_ESZ	8
17762306a36Sopenharmony_ci#define ESZ_MAX		ABI_0_ESZ
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic const struct vgic_its_abi its_table_abi_versions[] = {
18062306a36Sopenharmony_ci	[0] = {
18162306a36Sopenharmony_ci	 .cte_esz = ABI_0_ESZ,
18262306a36Sopenharmony_ci	 .dte_esz = ABI_0_ESZ,
18362306a36Sopenharmony_ci	 .ite_esz = ABI_0_ESZ,
18462306a36Sopenharmony_ci	 .save_tables = vgic_its_save_tables_v0,
18562306a36Sopenharmony_ci	 .restore_tables = vgic_its_restore_tables_v0,
18662306a36Sopenharmony_ci	 .commit = vgic_its_commit_v0,
18762306a36Sopenharmony_ci	},
18862306a36Sopenharmony_ci};
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci#define NR_ITS_ABIS	ARRAY_SIZE(its_table_abi_versions)
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciinline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	return &its_table_abi_versions[its->abi_rev];
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic int vgic_its_set_abi(struct vgic_its *its, u32 rev)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	const struct vgic_its_abi *abi;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	its->abi_rev = rev;
20262306a36Sopenharmony_ci	abi = vgic_its_get_abi(its);
20362306a36Sopenharmony_ci	return abi->commit(its);
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/*
20762306a36Sopenharmony_ci * Find and returns a device in the device table for an ITS.
20862306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_cistatic struct its_device *find_its_device(struct vgic_its *its, u32 device_id)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct its_device *device;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	list_for_each_entry(device, &its->device_list, dev_list)
21562306a36Sopenharmony_ci		if (device_id == device->device_id)
21662306a36Sopenharmony_ci			return device;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return NULL;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/*
22262306a36Sopenharmony_ci * Find and returns an interrupt translation table entry (ITTE) for a given
22362306a36Sopenharmony_ci * Device ID/Event ID pair on an ITS.
22462306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_cistatic struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
22762306a36Sopenharmony_ci				  u32 event_id)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct its_device *device;
23062306a36Sopenharmony_ci	struct its_ite *ite;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	device = find_its_device(its, device_id);
23362306a36Sopenharmony_ci	if (device == NULL)
23462306a36Sopenharmony_ci		return NULL;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	list_for_each_entry(ite, &device->itt_head, ite_list)
23762306a36Sopenharmony_ci		if (ite->event_id == event_id)
23862306a36Sopenharmony_ci			return ite;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	return NULL;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci/* To be used as an iterator this macro misses the enclosing parentheses */
24462306a36Sopenharmony_ci#define for_each_lpi_its(dev, ite, its) \
24562306a36Sopenharmony_ci	list_for_each_entry(dev, &(its)->device_list, dev_list) \
24662306a36Sopenharmony_ci		list_for_each_entry(ite, &(dev)->itt_head, ite_list)
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci#define GIC_LPI_OFFSET 8192
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci#define VITS_TYPER_IDBITS 16
25162306a36Sopenharmony_ci#define VITS_TYPER_DEVBITS 16
25262306a36Sopenharmony_ci#define VITS_DTE_MAX_DEVID_OFFSET	(BIT(14) - 1)
25362306a36Sopenharmony_ci#define VITS_ITE_MAX_EVENTID_OFFSET	(BIT(16) - 1)
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*
25662306a36Sopenharmony_ci * Finds and returns a collection in the ITS collection table.
25762306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_cistatic struct its_collection *find_collection(struct vgic_its *its, int coll_id)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct its_collection *collection;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	list_for_each_entry(collection, &its->collection_list, coll_list) {
26462306a36Sopenharmony_ci		if (coll_id == collection->collection_id)
26562306a36Sopenharmony_ci			return collection;
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return NULL;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci#define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
27262306a36Sopenharmony_ci#define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/*
27562306a36Sopenharmony_ci * Reads the configuration data for a given LPI from guest memory and
27662306a36Sopenharmony_ci * updates the fields in struct vgic_irq.
27762306a36Sopenharmony_ci * If filter_vcpu is not NULL, applies only if the IRQ is targeting this
27862306a36Sopenharmony_ci * VCPU. Unconditionally applies if filter_vcpu is NULL.
27962306a36Sopenharmony_ci */
28062306a36Sopenharmony_cistatic int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
28162306a36Sopenharmony_ci			     struct kvm_vcpu *filter_vcpu, bool needs_inv)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	u64 propbase = GICR_PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
28462306a36Sopenharmony_ci	u8 prop;
28562306a36Sopenharmony_ci	int ret;
28662306a36Sopenharmony_ci	unsigned long flags;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	ret = kvm_read_guest_lock(kvm, propbase + irq->intid - GIC_LPI_OFFSET,
28962306a36Sopenharmony_ci				  &prop, 1);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (ret)
29262306a36Sopenharmony_ci		return ret;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	raw_spin_lock_irqsave(&irq->irq_lock, flags);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (!filter_vcpu || filter_vcpu == irq->target_vcpu) {
29762306a36Sopenharmony_ci		irq->priority = LPI_PROP_PRIORITY(prop);
29862306a36Sopenharmony_ci		irq->enabled = LPI_PROP_ENABLE_BIT(prop);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		if (!irq->hw) {
30162306a36Sopenharmony_ci			vgic_queue_irq_unlock(kvm, irq, flags);
30262306a36Sopenharmony_ci			return 0;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (irq->hw)
30962306a36Sopenharmony_ci		return its_prop_update_vlpi(irq->host_irq, prop, needs_inv);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return 0;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/*
31562306a36Sopenharmony_ci * Create a snapshot of the current LPIs targeting @vcpu, so that we can
31662306a36Sopenharmony_ci * enumerate those LPIs without holding any lock.
31762306a36Sopenharmony_ci * Returns their number and puts the kmalloc'ed array into intid_ptr.
31862306a36Sopenharmony_ci */
31962306a36Sopenharmony_ciint vgic_copy_lpi_list(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 **intid_ptr)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
32262306a36Sopenharmony_ci	struct vgic_irq *irq;
32362306a36Sopenharmony_ci	unsigned long flags;
32462306a36Sopenharmony_ci	u32 *intids;
32562306a36Sopenharmony_ci	int irq_count, i = 0;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/*
32862306a36Sopenharmony_ci	 * There is an obvious race between allocating the array and LPIs
32962306a36Sopenharmony_ci	 * being mapped/unmapped. If we ended up here as a result of a
33062306a36Sopenharmony_ci	 * command, we're safe (locks are held, preventing another
33162306a36Sopenharmony_ci	 * command). If coming from another path (such as enabling LPIs),
33262306a36Sopenharmony_ci	 * we must be careful not to overrun the array.
33362306a36Sopenharmony_ci	 */
33462306a36Sopenharmony_ci	irq_count = READ_ONCE(dist->lpi_list_count);
33562306a36Sopenharmony_ci	intids = kmalloc_array(irq_count, sizeof(intids[0]), GFP_KERNEL_ACCOUNT);
33662306a36Sopenharmony_ci	if (!intids)
33762306a36Sopenharmony_ci		return -ENOMEM;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
34062306a36Sopenharmony_ci	list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
34162306a36Sopenharmony_ci		if (i == irq_count)
34262306a36Sopenharmony_ci			break;
34362306a36Sopenharmony_ci		/* We don't need to "get" the IRQ, as we hold the list lock. */
34462306a36Sopenharmony_ci		if (vcpu && irq->target_vcpu != vcpu)
34562306a36Sopenharmony_ci			continue;
34662306a36Sopenharmony_ci		intids[i++] = irq->intid;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	*intid_ptr = intids;
35162306a36Sopenharmony_ci	return i;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic int update_affinity(struct vgic_irq *irq, struct kvm_vcpu *vcpu)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	int ret = 0;
35762306a36Sopenharmony_ci	unsigned long flags;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&irq->irq_lock, flags);
36062306a36Sopenharmony_ci	irq->target_vcpu = vcpu;
36162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (irq->hw) {
36462306a36Sopenharmony_ci		struct its_vlpi_map map;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		ret = its_get_vlpi(irq->host_irq, &map);
36762306a36Sopenharmony_ci		if (ret)
36862306a36Sopenharmony_ci			return ret;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		if (map.vpe)
37162306a36Sopenharmony_ci			atomic_dec(&map.vpe->vlpi_count);
37262306a36Sopenharmony_ci		map.vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
37362306a36Sopenharmony_ci		atomic_inc(&map.vpe->vlpi_count);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		ret = its_map_vlpi(irq->host_irq, &map);
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return ret;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci/*
38262306a36Sopenharmony_ci * Promotes the ITS view of affinity of an ITTE (which redistributor this LPI
38362306a36Sopenharmony_ci * is targeting) to the VGIC's view, which deals with target VCPUs.
38462306a36Sopenharmony_ci * Needs to be called whenever either the collection for a LPIs has
38562306a36Sopenharmony_ci * changed or the collection itself got retargeted.
38662306a36Sopenharmony_ci */
38762306a36Sopenharmony_cistatic void update_affinity_ite(struct kvm *kvm, struct its_ite *ite)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct kvm_vcpu *vcpu;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (!its_is_collection_mapped(ite->collection))
39262306a36Sopenharmony_ci		return;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	vcpu = kvm_get_vcpu(kvm, ite->collection->target_addr);
39562306a36Sopenharmony_ci	update_affinity(ite->irq, vcpu);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci/*
39962306a36Sopenharmony_ci * Updates the target VCPU for every LPI targeting this collection.
40062306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_cistatic void update_affinity_collection(struct kvm *kvm, struct vgic_its *its,
40362306a36Sopenharmony_ci				       struct its_collection *coll)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct its_device *device;
40662306a36Sopenharmony_ci	struct its_ite *ite;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	for_each_lpi_its(device, ite, its) {
40962306a36Sopenharmony_ci		if (ite->collection != coll)
41062306a36Sopenharmony_ci			continue;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		update_affinity_ite(kvm, ite);
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic u32 max_lpis_propbaser(u64 propbaser)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	int nr_idbits = (propbaser & 0x1f) + 1;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return 1U << min(nr_idbits, INTERRUPT_ID_BITS_ITS);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci/*
42462306a36Sopenharmony_ci * Sync the pending table pending bit of LPIs targeting @vcpu
42562306a36Sopenharmony_ci * with our own data structures. This relies on the LPI being
42662306a36Sopenharmony_ci * mapped before.
42762306a36Sopenharmony_ci */
42862306a36Sopenharmony_cistatic int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	gpa_t pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
43162306a36Sopenharmony_ci	struct vgic_irq *irq;
43262306a36Sopenharmony_ci	int last_byte_offset = -1;
43362306a36Sopenharmony_ci	int ret = 0;
43462306a36Sopenharmony_ci	u32 *intids;
43562306a36Sopenharmony_ci	int nr_irqs, i;
43662306a36Sopenharmony_ci	unsigned long flags;
43762306a36Sopenharmony_ci	u8 pendmask;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	nr_irqs = vgic_copy_lpi_list(vcpu->kvm, vcpu, &intids);
44062306a36Sopenharmony_ci	if (nr_irqs < 0)
44162306a36Sopenharmony_ci		return nr_irqs;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	for (i = 0; i < nr_irqs; i++) {
44462306a36Sopenharmony_ci		int byte_offset, bit_nr;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		byte_offset = intids[i] / BITS_PER_BYTE;
44762306a36Sopenharmony_ci		bit_nr = intids[i] % BITS_PER_BYTE;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		/*
45062306a36Sopenharmony_ci		 * For contiguously allocated LPIs chances are we just read
45162306a36Sopenharmony_ci		 * this very same byte in the last iteration. Reuse that.
45262306a36Sopenharmony_ci		 */
45362306a36Sopenharmony_ci		if (byte_offset != last_byte_offset) {
45462306a36Sopenharmony_ci			ret = kvm_read_guest_lock(vcpu->kvm,
45562306a36Sopenharmony_ci						  pendbase + byte_offset,
45662306a36Sopenharmony_ci						  &pendmask, 1);
45762306a36Sopenharmony_ci			if (ret) {
45862306a36Sopenharmony_ci				kfree(intids);
45962306a36Sopenharmony_ci				return ret;
46062306a36Sopenharmony_ci			}
46162306a36Sopenharmony_ci			last_byte_offset = byte_offset;
46262306a36Sopenharmony_ci		}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		irq = vgic_get_irq(vcpu->kvm, NULL, intids[i]);
46562306a36Sopenharmony_ci		if (!irq)
46662306a36Sopenharmony_ci			continue;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		raw_spin_lock_irqsave(&irq->irq_lock, flags);
46962306a36Sopenharmony_ci		irq->pending_latch = pendmask & (1U << bit_nr);
47062306a36Sopenharmony_ci		vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
47162306a36Sopenharmony_ci		vgic_put_irq(vcpu->kvm, irq);
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	kfree(intids);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return ret;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
48062306a36Sopenharmony_ci					      struct vgic_its *its,
48162306a36Sopenharmony_ci					      gpa_t addr, unsigned int len)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
48462306a36Sopenharmony_ci	u64 reg = GITS_TYPER_PLPIS;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/*
48762306a36Sopenharmony_ci	 * We use linear CPU numbers for redistributor addressing,
48862306a36Sopenharmony_ci	 * so GITS_TYPER.PTA is 0.
48962306a36Sopenharmony_ci	 * Also we force all PROPBASER registers to be the same, so
49062306a36Sopenharmony_ci	 * CommonLPIAff is 0 as well.
49162306a36Sopenharmony_ci	 * To avoid memory waste in the guest, we keep the number of IDBits and
49262306a36Sopenharmony_ci	 * DevBits low - as least for the time being.
49362306a36Sopenharmony_ci	 */
49462306a36Sopenharmony_ci	reg |= GIC_ENCODE_SZ(VITS_TYPER_DEVBITS, 5) << GITS_TYPER_DEVBITS_SHIFT;
49562306a36Sopenharmony_ci	reg |= GIC_ENCODE_SZ(VITS_TYPER_IDBITS, 5) << GITS_TYPER_IDBITS_SHIFT;
49662306a36Sopenharmony_ci	reg |= GIC_ENCODE_SZ(abi->ite_esz, 4) << GITS_TYPER_ITT_ENTRY_SIZE_SHIFT;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return extract_bytes(reg, addr & 7, len);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic unsigned long vgic_mmio_read_its_iidr(struct kvm *kvm,
50262306a36Sopenharmony_ci					     struct vgic_its *its,
50362306a36Sopenharmony_ci					     gpa_t addr, unsigned int len)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	u32 val;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	val = (its->abi_rev << GITS_IIDR_REV_SHIFT) & GITS_IIDR_REV_MASK;
50862306a36Sopenharmony_ci	val |= (PRODUCT_ID_KVM << GITS_IIDR_PRODUCTID_SHIFT) | IMPLEMENTER_ARM;
50962306a36Sopenharmony_ci	return val;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic int vgic_mmio_uaccess_write_its_iidr(struct kvm *kvm,
51362306a36Sopenharmony_ci					    struct vgic_its *its,
51462306a36Sopenharmony_ci					    gpa_t addr, unsigned int len,
51562306a36Sopenharmony_ci					    unsigned long val)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	u32 rev = GITS_IIDR_REV(val);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (rev >= NR_ITS_ABIS)
52062306a36Sopenharmony_ci		return -EINVAL;
52162306a36Sopenharmony_ci	return vgic_its_set_abi(its, rev);
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic unsigned long vgic_mmio_read_its_idregs(struct kvm *kvm,
52562306a36Sopenharmony_ci					       struct vgic_its *its,
52662306a36Sopenharmony_ci					       gpa_t addr, unsigned int len)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	switch (addr & 0xffff) {
52962306a36Sopenharmony_ci	case GITS_PIDR0:
53062306a36Sopenharmony_ci		return 0x92;	/* part number, bits[7:0] */
53162306a36Sopenharmony_ci	case GITS_PIDR1:
53262306a36Sopenharmony_ci		return 0xb4;	/* part number, bits[11:8] */
53362306a36Sopenharmony_ci	case GITS_PIDR2:
53462306a36Sopenharmony_ci		return GIC_PIDR2_ARCH_GICv3 | 0x0b;
53562306a36Sopenharmony_ci	case GITS_PIDR4:
53662306a36Sopenharmony_ci		return 0x40;	/* This is a 64K software visible page */
53762306a36Sopenharmony_ci	/* The following are the ID registers for (any) GIC. */
53862306a36Sopenharmony_ci	case GITS_CIDR0:
53962306a36Sopenharmony_ci		return 0x0d;
54062306a36Sopenharmony_ci	case GITS_CIDR1:
54162306a36Sopenharmony_ci		return 0xf0;
54262306a36Sopenharmony_ci	case GITS_CIDR2:
54362306a36Sopenharmony_ci		return 0x05;
54462306a36Sopenharmony_ci	case GITS_CIDR3:
54562306a36Sopenharmony_ci		return 0xb1;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	return 0;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic struct vgic_irq *__vgic_its_check_cache(struct vgic_dist *dist,
55262306a36Sopenharmony_ci					       phys_addr_t db,
55362306a36Sopenharmony_ci					       u32 devid, u32 eventid)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	struct vgic_translation_cache_entry *cte;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	list_for_each_entry(cte, &dist->lpi_translation_cache, entry) {
55862306a36Sopenharmony_ci		/*
55962306a36Sopenharmony_ci		 * If we hit a NULL entry, there is nothing after this
56062306a36Sopenharmony_ci		 * point.
56162306a36Sopenharmony_ci		 */
56262306a36Sopenharmony_ci		if (!cte->irq)
56362306a36Sopenharmony_ci			break;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		if (cte->db != db || cte->devid != devid ||
56662306a36Sopenharmony_ci		    cte->eventid != eventid)
56762306a36Sopenharmony_ci			continue;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci		/*
57062306a36Sopenharmony_ci		 * Move this entry to the head, as it is the most
57162306a36Sopenharmony_ci		 * recently used.
57262306a36Sopenharmony_ci		 */
57362306a36Sopenharmony_ci		if (!list_is_first(&cte->entry, &dist->lpi_translation_cache))
57462306a36Sopenharmony_ci			list_move(&cte->entry, &dist->lpi_translation_cache);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci		return cte->irq;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	return NULL;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db,
58362306a36Sopenharmony_ci					     u32 devid, u32 eventid)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
58662306a36Sopenharmony_ci	struct vgic_irq *irq;
58762306a36Sopenharmony_ci	unsigned long flags;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	irq = __vgic_its_check_cache(dist, db, devid, eventid);
59262306a36Sopenharmony_ci	if (irq)
59362306a36Sopenharmony_ci		vgic_get_irq_kref(irq);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	return irq;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its,
60162306a36Sopenharmony_ci				       u32 devid, u32 eventid,
60262306a36Sopenharmony_ci				       struct vgic_irq *irq)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
60562306a36Sopenharmony_ci	struct vgic_translation_cache_entry *cte;
60662306a36Sopenharmony_ci	unsigned long flags;
60762306a36Sopenharmony_ci	phys_addr_t db;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Do not cache a directly injected interrupt */
61062306a36Sopenharmony_ci	if (irq->hw)
61162306a36Sopenharmony_ci		return;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (unlikely(list_empty(&dist->lpi_translation_cache)))
61662306a36Sopenharmony_ci		goto out;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/*
61962306a36Sopenharmony_ci	 * We could have raced with another CPU caching the same
62062306a36Sopenharmony_ci	 * translation behind our back, so let's check it is not in
62162306a36Sopenharmony_ci	 * already
62262306a36Sopenharmony_ci	 */
62362306a36Sopenharmony_ci	db = its->vgic_its_base + GITS_TRANSLATER;
62462306a36Sopenharmony_ci	if (__vgic_its_check_cache(dist, db, devid, eventid))
62562306a36Sopenharmony_ci		goto out;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/* Always reuse the last entry (LRU policy) */
62862306a36Sopenharmony_ci	cte = list_last_entry(&dist->lpi_translation_cache,
62962306a36Sopenharmony_ci			      typeof(*cte), entry);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	/*
63262306a36Sopenharmony_ci	 * Caching the translation implies having an extra reference
63362306a36Sopenharmony_ci	 * to the interrupt, so drop the potential reference on what
63462306a36Sopenharmony_ci	 * was in the cache, and increment it on the new interrupt.
63562306a36Sopenharmony_ci	 */
63662306a36Sopenharmony_ci	if (cte->irq)
63762306a36Sopenharmony_ci		__vgic_put_lpi_locked(kvm, cte->irq);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	vgic_get_irq_kref(irq);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	cte->db		= db;
64262306a36Sopenharmony_ci	cte->devid	= devid;
64362306a36Sopenharmony_ci	cte->eventid	= eventid;
64462306a36Sopenharmony_ci	cte->irq	= irq;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* Move the new translation to the head of the list */
64762306a36Sopenharmony_ci	list_move(&cte->entry, &dist->lpi_translation_cache);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ciout:
65062306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_civoid vgic_its_invalidate_cache(struct kvm *kvm)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
65662306a36Sopenharmony_ci	struct vgic_translation_cache_entry *cte;
65762306a36Sopenharmony_ci	unsigned long flags;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	list_for_each_entry(cte, &dist->lpi_translation_cache, entry) {
66262306a36Sopenharmony_ci		/*
66362306a36Sopenharmony_ci		 * If we hit a NULL entry, there is nothing after this
66462306a36Sopenharmony_ci		 * point.
66562306a36Sopenharmony_ci		 */
66662306a36Sopenharmony_ci		if (!cte->irq)
66762306a36Sopenharmony_ci			break;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		__vgic_put_lpi_locked(kvm, cte->irq);
67062306a36Sopenharmony_ci		cte->irq = NULL;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciint vgic_its_resolve_lpi(struct kvm *kvm, struct vgic_its *its,
67762306a36Sopenharmony_ci			 u32 devid, u32 eventid, struct vgic_irq **irq)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct kvm_vcpu *vcpu;
68062306a36Sopenharmony_ci	struct its_ite *ite;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (!its->enabled)
68362306a36Sopenharmony_ci		return -EBUSY;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	ite = find_ite(its, devid, eventid);
68662306a36Sopenharmony_ci	if (!ite || !its_is_collection_mapped(ite->collection))
68762306a36Sopenharmony_ci		return E_ITS_INT_UNMAPPED_INTERRUPT;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	vcpu = kvm_get_vcpu(kvm, ite->collection->target_addr);
69062306a36Sopenharmony_ci	if (!vcpu)
69162306a36Sopenharmony_ci		return E_ITS_INT_UNMAPPED_INTERRUPT;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	if (!vgic_lpis_enabled(vcpu))
69462306a36Sopenharmony_ci		return -EBUSY;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	vgic_its_cache_translation(kvm, its, devid, eventid, ite->irq);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	*irq = ite->irq;
69962306a36Sopenharmony_ci	return 0;
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistruct vgic_its *vgic_msi_to_its(struct kvm *kvm, struct kvm_msi *msi)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	u64 address;
70562306a36Sopenharmony_ci	struct kvm_io_device *kvm_io_dev;
70662306a36Sopenharmony_ci	struct vgic_io_device *iodev;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	if (!vgic_has_its(kvm))
70962306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (!(msi->flags & KVM_MSI_VALID_DEVID))
71262306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	address = (u64)msi->address_hi << 32 | msi->address_lo;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	kvm_io_dev = kvm_io_bus_get_dev(kvm, KVM_MMIO_BUS, address);
71762306a36Sopenharmony_ci	if (!kvm_io_dev)
71862306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (kvm_io_dev->ops != &kvm_io_gic_ops)
72162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	iodev = container_of(kvm_io_dev, struct vgic_io_device, dev);
72462306a36Sopenharmony_ci	if (iodev->iodev_type != IODEV_ITS)
72562306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	return iodev->its;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci/*
73162306a36Sopenharmony_ci * Find the target VCPU and the LPI number for a given devid/eventid pair
73262306a36Sopenharmony_ci * and make this IRQ pending, possibly injecting it.
73362306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
73462306a36Sopenharmony_ci * Returns 0 on success, a positive error value for any ITS mapping
73562306a36Sopenharmony_ci * related errors and negative error values for generic errors.
73662306a36Sopenharmony_ci */
73762306a36Sopenharmony_cistatic int vgic_its_trigger_msi(struct kvm *kvm, struct vgic_its *its,
73862306a36Sopenharmony_ci				u32 devid, u32 eventid)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct vgic_irq *irq = NULL;
74162306a36Sopenharmony_ci	unsigned long flags;
74262306a36Sopenharmony_ci	int err;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	err = vgic_its_resolve_lpi(kvm, its, devid, eventid, &irq);
74562306a36Sopenharmony_ci	if (err)
74662306a36Sopenharmony_ci		return err;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (irq->hw)
74962306a36Sopenharmony_ci		return irq_set_irqchip_state(irq->host_irq,
75062306a36Sopenharmony_ci					     IRQCHIP_STATE_PENDING, true);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	raw_spin_lock_irqsave(&irq->irq_lock, flags);
75362306a36Sopenharmony_ci	irq->pending_latch = true;
75462306a36Sopenharmony_ci	vgic_queue_irq_unlock(kvm, irq, flags);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	return 0;
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ciint vgic_its_inject_cached_translation(struct kvm *kvm, struct kvm_msi *msi)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	struct vgic_irq *irq;
76262306a36Sopenharmony_ci	unsigned long flags;
76362306a36Sopenharmony_ci	phys_addr_t db;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	db = (u64)msi->address_hi << 32 | msi->address_lo;
76662306a36Sopenharmony_ci	irq = vgic_its_check_cache(kvm, db, msi->devid, msi->data);
76762306a36Sopenharmony_ci	if (!irq)
76862306a36Sopenharmony_ci		return -EWOULDBLOCK;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	raw_spin_lock_irqsave(&irq->irq_lock, flags);
77162306a36Sopenharmony_ci	irq->pending_latch = true;
77262306a36Sopenharmony_ci	vgic_queue_irq_unlock(kvm, irq, flags);
77362306a36Sopenharmony_ci	vgic_put_irq(kvm, irq);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	return 0;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci/*
77962306a36Sopenharmony_ci * Queries the KVM IO bus framework to get the ITS pointer from the given
78062306a36Sopenharmony_ci * doorbell address.
78162306a36Sopenharmony_ci * We then call vgic_its_trigger_msi() with the decoded data.
78262306a36Sopenharmony_ci * According to the KVM_SIGNAL_MSI API description returns 1 on success.
78362306a36Sopenharmony_ci */
78462306a36Sopenharmony_ciint vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct vgic_its *its;
78762306a36Sopenharmony_ci	int ret;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	if (!vgic_its_inject_cached_translation(kvm, msi))
79062306a36Sopenharmony_ci		return 1;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	its = vgic_msi_to_its(kvm, msi);
79362306a36Sopenharmony_ci	if (IS_ERR(its))
79462306a36Sopenharmony_ci		return PTR_ERR(its);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	mutex_lock(&its->its_lock);
79762306a36Sopenharmony_ci	ret = vgic_its_trigger_msi(kvm, its, msi->devid, msi->data);
79862306a36Sopenharmony_ci	mutex_unlock(&its->its_lock);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	if (ret < 0)
80162306a36Sopenharmony_ci		return ret;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	/*
80462306a36Sopenharmony_ci	 * KVM_SIGNAL_MSI demands a return value > 0 for success and 0
80562306a36Sopenharmony_ci	 * if the guest has blocked the MSI. So we map any LPI mapping
80662306a36Sopenharmony_ci	 * related error to that.
80762306a36Sopenharmony_ci	 */
80862306a36Sopenharmony_ci	if (ret)
80962306a36Sopenharmony_ci		return 0;
81062306a36Sopenharmony_ci	else
81162306a36Sopenharmony_ci		return 1;
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci/* Requires the its_lock to be held. */
81562306a36Sopenharmony_cistatic void its_free_ite(struct kvm *kvm, struct its_ite *ite)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	list_del(&ite->ite_list);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	/* This put matches the get in vgic_add_lpi. */
82062306a36Sopenharmony_ci	if (ite->irq) {
82162306a36Sopenharmony_ci		if (ite->irq->hw)
82262306a36Sopenharmony_ci			WARN_ON(its_unmap_vlpi(ite->irq->host_irq));
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		vgic_put_irq(kvm, ite->irq);
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	kfree(ite);
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	return (le64_to_cpu(its_cmd[word]) >> shift) & (BIT_ULL(size) - 1);
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci#define its_cmd_get_command(cmd)	its_cmd_mask_field(cmd, 0,  0,  8)
83662306a36Sopenharmony_ci#define its_cmd_get_deviceid(cmd)	its_cmd_mask_field(cmd, 0, 32, 32)
83762306a36Sopenharmony_ci#define its_cmd_get_size(cmd)		(its_cmd_mask_field(cmd, 1,  0,  5) + 1)
83862306a36Sopenharmony_ci#define its_cmd_get_id(cmd)		its_cmd_mask_field(cmd, 1,  0, 32)
83962306a36Sopenharmony_ci#define its_cmd_get_physical_id(cmd)	its_cmd_mask_field(cmd, 1, 32, 32)
84062306a36Sopenharmony_ci#define its_cmd_get_collection(cmd)	its_cmd_mask_field(cmd, 2,  0, 16)
84162306a36Sopenharmony_ci#define its_cmd_get_ittaddr(cmd)	(its_cmd_mask_field(cmd, 2,  8, 44) << 8)
84262306a36Sopenharmony_ci#define its_cmd_get_target_addr(cmd)	its_cmd_mask_field(cmd, 2, 16, 32)
84362306a36Sopenharmony_ci#define its_cmd_get_validbit(cmd)	its_cmd_mask_field(cmd, 2, 63,  1)
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci/*
84662306a36Sopenharmony_ci * The DISCARD command frees an Interrupt Translation Table Entry (ITTE).
84762306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
84862306a36Sopenharmony_ci */
84962306a36Sopenharmony_cistatic int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its,
85062306a36Sopenharmony_ci				       u64 *its_cmd)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
85362306a36Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
85462306a36Sopenharmony_ci	struct its_ite *ite;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	ite = find_ite(its, device_id, event_id);
85762306a36Sopenharmony_ci	if (ite && its_is_collection_mapped(ite->collection)) {
85862306a36Sopenharmony_ci		/*
85962306a36Sopenharmony_ci		 * Though the spec talks about removing the pending state, we
86062306a36Sopenharmony_ci		 * don't bother here since we clear the ITTE anyway and the
86162306a36Sopenharmony_ci		 * pending state is a property of the ITTE struct.
86262306a36Sopenharmony_ci		 */
86362306a36Sopenharmony_ci		vgic_its_invalidate_cache(kvm);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci		its_free_ite(kvm, ite);
86662306a36Sopenharmony_ci		return 0;
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci/*
87362306a36Sopenharmony_ci * The MOVI command moves an ITTE to a different collection.
87462306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
87562306a36Sopenharmony_ci */
87662306a36Sopenharmony_cistatic int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
87762306a36Sopenharmony_ci				    u64 *its_cmd)
87862306a36Sopenharmony_ci{
87962306a36Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
88062306a36Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
88162306a36Sopenharmony_ci	u32 coll_id = its_cmd_get_collection(its_cmd);
88262306a36Sopenharmony_ci	struct kvm_vcpu *vcpu;
88362306a36Sopenharmony_ci	struct its_ite *ite;
88462306a36Sopenharmony_ci	struct its_collection *collection;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	ite = find_ite(its, device_id, event_id);
88762306a36Sopenharmony_ci	if (!ite)
88862306a36Sopenharmony_ci		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	if (!its_is_collection_mapped(ite->collection))
89162306a36Sopenharmony_ci		return E_ITS_MOVI_UNMAPPED_COLLECTION;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	collection = find_collection(its, coll_id);
89462306a36Sopenharmony_ci	if (!its_is_collection_mapped(collection))
89562306a36Sopenharmony_ci		return E_ITS_MOVI_UNMAPPED_COLLECTION;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	ite->collection = collection;
89862306a36Sopenharmony_ci	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	vgic_its_invalidate_cache(kvm);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	return update_affinity(ite->irq, vcpu);
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cistatic bool __is_visible_gfn_locked(struct vgic_its *its, gpa_t gpa)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	gfn_t gfn = gpa >> PAGE_SHIFT;
90862306a36Sopenharmony_ci	int idx;
90962306a36Sopenharmony_ci	bool ret;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	idx = srcu_read_lock(&its->dev->kvm->srcu);
91262306a36Sopenharmony_ci	ret = kvm_is_visible_gfn(its->dev->kvm, gfn);
91362306a36Sopenharmony_ci	srcu_read_unlock(&its->dev->kvm->srcu, idx);
91462306a36Sopenharmony_ci	return ret;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci/*
91862306a36Sopenharmony_ci * Check whether an ID can be stored into the corresponding guest table.
91962306a36Sopenharmony_ci * For a direct table this is pretty easy, but gets a bit nasty for
92062306a36Sopenharmony_ci * indirect tables. We check whether the resulting guest physical address
92162306a36Sopenharmony_ci * is actually valid (covered by a memslot and guest accessible).
92262306a36Sopenharmony_ci * For this we have to read the respective first level entry.
92362306a36Sopenharmony_ci */
92462306a36Sopenharmony_cistatic bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id,
92562306a36Sopenharmony_ci			      gpa_t *eaddr)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
92862306a36Sopenharmony_ci	u64 indirect_ptr, type = GITS_BASER_TYPE(baser);
92962306a36Sopenharmony_ci	phys_addr_t base = GITS_BASER_ADDR_48_to_52(baser);
93062306a36Sopenharmony_ci	int esz = GITS_BASER_ENTRY_SIZE(baser);
93162306a36Sopenharmony_ci	int index;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	switch (type) {
93462306a36Sopenharmony_ci	case GITS_BASER_TYPE_DEVICE:
93562306a36Sopenharmony_ci		if (id >= BIT_ULL(VITS_TYPER_DEVBITS))
93662306a36Sopenharmony_ci			return false;
93762306a36Sopenharmony_ci		break;
93862306a36Sopenharmony_ci	case GITS_BASER_TYPE_COLLECTION:
93962306a36Sopenharmony_ci		/* as GITS_TYPER.CIL == 0, ITS supports 16-bit collection ID */
94062306a36Sopenharmony_ci		if (id >= BIT_ULL(16))
94162306a36Sopenharmony_ci			return false;
94262306a36Sopenharmony_ci		break;
94362306a36Sopenharmony_ci	default:
94462306a36Sopenharmony_ci		return false;
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	if (!(baser & GITS_BASER_INDIRECT)) {
94862306a36Sopenharmony_ci		phys_addr_t addr;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		if (id >= (l1_tbl_size / esz))
95162306a36Sopenharmony_ci			return false;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci		addr = base + id * esz;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci		if (eaddr)
95662306a36Sopenharmony_ci			*eaddr = addr;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci		return __is_visible_gfn_locked(its, addr);
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	/* calculate and check the index into the 1st level */
96262306a36Sopenharmony_ci	index = id / (SZ_64K / esz);
96362306a36Sopenharmony_ci	if (index >= (l1_tbl_size / sizeof(u64)))
96462306a36Sopenharmony_ci		return false;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	/* Each 1st level entry is represented by a 64-bit value. */
96762306a36Sopenharmony_ci	if (kvm_read_guest_lock(its->dev->kvm,
96862306a36Sopenharmony_ci			   base + index * sizeof(indirect_ptr),
96962306a36Sopenharmony_ci			   &indirect_ptr, sizeof(indirect_ptr)))
97062306a36Sopenharmony_ci		return false;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	indirect_ptr = le64_to_cpu(indirect_ptr);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	/* check the valid bit of the first level entry */
97562306a36Sopenharmony_ci	if (!(indirect_ptr & BIT_ULL(63)))
97662306a36Sopenharmony_ci		return false;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	/* Mask the guest physical address and calculate the frame number. */
97962306a36Sopenharmony_ci	indirect_ptr &= GENMASK_ULL(51, 16);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	/* Find the address of the actual entry */
98262306a36Sopenharmony_ci	index = id % (SZ_64K / esz);
98362306a36Sopenharmony_ci	indirect_ptr += index * esz;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (eaddr)
98662306a36Sopenharmony_ci		*eaddr = indirect_ptr;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	return __is_visible_gfn_locked(its, indirect_ptr);
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci/*
99262306a36Sopenharmony_ci * Check whether an event ID can be stored in the corresponding Interrupt
99362306a36Sopenharmony_ci * Translation Table, which starts at device->itt_addr.
99462306a36Sopenharmony_ci */
99562306a36Sopenharmony_cistatic bool vgic_its_check_event_id(struct vgic_its *its, struct its_device *device,
99662306a36Sopenharmony_ci		u32 event_id)
99762306a36Sopenharmony_ci{
99862306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
99962306a36Sopenharmony_ci	int ite_esz = abi->ite_esz;
100062306a36Sopenharmony_ci	gpa_t gpa;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	/* max table size is: BIT_ULL(device->num_eventid_bits) * ite_esz */
100362306a36Sopenharmony_ci	if (event_id >= BIT_ULL(device->num_eventid_bits))
100462306a36Sopenharmony_ci		return false;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	gpa = device->itt_addr + event_id * ite_esz;
100762306a36Sopenharmony_ci	return __is_visible_gfn_locked(its, gpa);
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci/*
101162306a36Sopenharmony_ci * Add a new collection into the ITS collection table.
101262306a36Sopenharmony_ci * Returns 0 on success, and a negative error value for generic errors.
101362306a36Sopenharmony_ci */
101462306a36Sopenharmony_cistatic int vgic_its_alloc_collection(struct vgic_its *its,
101562306a36Sopenharmony_ci				     struct its_collection **colp,
101662306a36Sopenharmony_ci				     u32 coll_id)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	struct its_collection *collection;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	collection = kzalloc(sizeof(*collection), GFP_KERNEL_ACCOUNT);
102162306a36Sopenharmony_ci	if (!collection)
102262306a36Sopenharmony_ci		return -ENOMEM;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	collection->collection_id = coll_id;
102562306a36Sopenharmony_ci	collection->target_addr = COLLECTION_NOT_MAPPED;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	list_add_tail(&collection->coll_list, &its->collection_list);
102862306a36Sopenharmony_ci	*colp = collection;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	return 0;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_cistatic void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	struct its_collection *collection;
103662306a36Sopenharmony_ci	struct its_device *device;
103762306a36Sopenharmony_ci	struct its_ite *ite;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	/*
104062306a36Sopenharmony_ci	 * Clearing the mapping for that collection ID removes the
104162306a36Sopenharmony_ci	 * entry from the list. If there wasn't any before, we can
104262306a36Sopenharmony_ci	 * go home early.
104362306a36Sopenharmony_ci	 */
104462306a36Sopenharmony_ci	collection = find_collection(its, coll_id);
104562306a36Sopenharmony_ci	if (!collection)
104662306a36Sopenharmony_ci		return;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	for_each_lpi_its(device, ite, its)
104962306a36Sopenharmony_ci		if (ite->collection &&
105062306a36Sopenharmony_ci		    ite->collection->collection_id == coll_id)
105162306a36Sopenharmony_ci			ite->collection = NULL;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	list_del(&collection->coll_list);
105462306a36Sopenharmony_ci	kfree(collection);
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci/* Must be called with its_lock mutex held */
105862306a36Sopenharmony_cistatic struct its_ite *vgic_its_alloc_ite(struct its_device *device,
105962306a36Sopenharmony_ci					  struct its_collection *collection,
106062306a36Sopenharmony_ci					  u32 event_id)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	struct its_ite *ite;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	ite = kzalloc(sizeof(*ite), GFP_KERNEL_ACCOUNT);
106562306a36Sopenharmony_ci	if (!ite)
106662306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	ite->event_id	= event_id;
106962306a36Sopenharmony_ci	ite->collection = collection;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	list_add_tail(&ite->ite_list, &device->itt_head);
107262306a36Sopenharmony_ci	return ite;
107362306a36Sopenharmony_ci}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci/*
107662306a36Sopenharmony_ci * The MAPTI and MAPI commands map LPIs to ITTEs.
107762306a36Sopenharmony_ci * Must be called with its_lock mutex held.
107862306a36Sopenharmony_ci */
107962306a36Sopenharmony_cistatic int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
108062306a36Sopenharmony_ci				    u64 *its_cmd)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
108362306a36Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
108462306a36Sopenharmony_ci	u32 coll_id = its_cmd_get_collection(its_cmd);
108562306a36Sopenharmony_ci	struct its_ite *ite;
108662306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = NULL;
108762306a36Sopenharmony_ci	struct its_device *device;
108862306a36Sopenharmony_ci	struct its_collection *collection, *new_coll = NULL;
108962306a36Sopenharmony_ci	struct vgic_irq *irq;
109062306a36Sopenharmony_ci	int lpi_nr;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	device = find_its_device(its, device_id);
109362306a36Sopenharmony_ci	if (!device)
109462306a36Sopenharmony_ci		return E_ITS_MAPTI_UNMAPPED_DEVICE;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	if (!vgic_its_check_event_id(its, device, event_id))
109762306a36Sopenharmony_ci		return E_ITS_MAPTI_ID_OOR;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	if (its_cmd_get_command(its_cmd) == GITS_CMD_MAPTI)
110062306a36Sopenharmony_ci		lpi_nr = its_cmd_get_physical_id(its_cmd);
110162306a36Sopenharmony_ci	else
110262306a36Sopenharmony_ci		lpi_nr = event_id;
110362306a36Sopenharmony_ci	if (lpi_nr < GIC_LPI_OFFSET ||
110462306a36Sopenharmony_ci	    lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser))
110562306a36Sopenharmony_ci		return E_ITS_MAPTI_PHYSICALID_OOR;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	/* If there is an existing mapping, behavior is UNPREDICTABLE. */
110862306a36Sopenharmony_ci	if (find_ite(its, device_id, event_id))
110962306a36Sopenharmony_ci		return 0;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	collection = find_collection(its, coll_id);
111262306a36Sopenharmony_ci	if (!collection) {
111362306a36Sopenharmony_ci		int ret;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci		if (!vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL))
111662306a36Sopenharmony_ci			return E_ITS_MAPC_COLLECTION_OOR;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci		ret = vgic_its_alloc_collection(its, &collection, coll_id);
111962306a36Sopenharmony_ci		if (ret)
112062306a36Sopenharmony_ci			return ret;
112162306a36Sopenharmony_ci		new_coll = collection;
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	ite = vgic_its_alloc_ite(device, collection, event_id);
112562306a36Sopenharmony_ci	if (IS_ERR(ite)) {
112662306a36Sopenharmony_ci		if (new_coll)
112762306a36Sopenharmony_ci			vgic_its_free_collection(its, coll_id);
112862306a36Sopenharmony_ci		return PTR_ERR(ite);
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	if (its_is_collection_mapped(collection))
113262306a36Sopenharmony_ci		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	irq = vgic_add_lpi(kvm, lpi_nr, vcpu);
113562306a36Sopenharmony_ci	if (IS_ERR(irq)) {
113662306a36Sopenharmony_ci		if (new_coll)
113762306a36Sopenharmony_ci			vgic_its_free_collection(its, coll_id);
113862306a36Sopenharmony_ci		its_free_ite(kvm, ite);
113962306a36Sopenharmony_ci		return PTR_ERR(irq);
114062306a36Sopenharmony_ci	}
114162306a36Sopenharmony_ci	ite->irq = irq;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	return 0;
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci/* Requires the its_lock to be held. */
114762306a36Sopenharmony_cistatic void vgic_its_free_device(struct kvm *kvm, struct its_device *device)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	struct its_ite *ite, *temp;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	/*
115262306a36Sopenharmony_ci	 * The spec says that unmapping a device with still valid
115362306a36Sopenharmony_ci	 * ITTEs associated is UNPREDICTABLE. We remove all ITTEs,
115462306a36Sopenharmony_ci	 * since we cannot leave the memory unreferenced.
115562306a36Sopenharmony_ci	 */
115662306a36Sopenharmony_ci	list_for_each_entry_safe(ite, temp, &device->itt_head, ite_list)
115762306a36Sopenharmony_ci		its_free_ite(kvm, ite);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	vgic_its_invalidate_cache(kvm);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	list_del(&device->dev_list);
116262306a36Sopenharmony_ci	kfree(device);
116362306a36Sopenharmony_ci}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci/* its lock must be held */
116662306a36Sopenharmony_cistatic void vgic_its_free_device_list(struct kvm *kvm, struct vgic_its *its)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci	struct its_device *cur, *temp;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	list_for_each_entry_safe(cur, temp, &its->device_list, dev_list)
117162306a36Sopenharmony_ci		vgic_its_free_device(kvm, cur);
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci/* its lock must be held */
117562306a36Sopenharmony_cistatic void vgic_its_free_collection_list(struct kvm *kvm, struct vgic_its *its)
117662306a36Sopenharmony_ci{
117762306a36Sopenharmony_ci	struct its_collection *cur, *temp;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	list_for_each_entry_safe(cur, temp, &its->collection_list, coll_list)
118062306a36Sopenharmony_ci		vgic_its_free_collection(its, cur->collection_id);
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci/* Must be called with its_lock mutex held */
118462306a36Sopenharmony_cistatic struct its_device *vgic_its_alloc_device(struct vgic_its *its,
118562306a36Sopenharmony_ci						u32 device_id, gpa_t itt_addr,
118662306a36Sopenharmony_ci						u8 num_eventid_bits)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct its_device *device;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	device = kzalloc(sizeof(*device), GFP_KERNEL_ACCOUNT);
119162306a36Sopenharmony_ci	if (!device)
119262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	device->device_id = device_id;
119562306a36Sopenharmony_ci	device->itt_addr = itt_addr;
119662306a36Sopenharmony_ci	device->num_eventid_bits = num_eventid_bits;
119762306a36Sopenharmony_ci	INIT_LIST_HEAD(&device->itt_head);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	list_add_tail(&device->dev_list, &its->device_list);
120062306a36Sopenharmony_ci	return device;
120162306a36Sopenharmony_ci}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci/*
120462306a36Sopenharmony_ci * MAPD maps or unmaps a device ID to Interrupt Translation Tables (ITTs).
120562306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
120662306a36Sopenharmony_ci */
120762306a36Sopenharmony_cistatic int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
120862306a36Sopenharmony_ci				    u64 *its_cmd)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
121162306a36Sopenharmony_ci	bool valid = its_cmd_get_validbit(its_cmd);
121262306a36Sopenharmony_ci	u8 num_eventid_bits = its_cmd_get_size(its_cmd);
121362306a36Sopenharmony_ci	gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
121462306a36Sopenharmony_ci	struct its_device *device;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	if (!vgic_its_check_id(its, its->baser_device_table, device_id, NULL))
121762306a36Sopenharmony_ci		return E_ITS_MAPD_DEVICE_OOR;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (valid && num_eventid_bits > VITS_TYPER_IDBITS)
122062306a36Sopenharmony_ci		return E_ITS_MAPD_ITTSIZE_OOR;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	device = find_its_device(its, device_id);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	/*
122562306a36Sopenharmony_ci	 * The spec says that calling MAPD on an already mapped device
122662306a36Sopenharmony_ci	 * invalidates all cached data for this device. We implement this
122762306a36Sopenharmony_ci	 * by removing the mapping and re-establishing it.
122862306a36Sopenharmony_ci	 */
122962306a36Sopenharmony_ci	if (device)
123062306a36Sopenharmony_ci		vgic_its_free_device(kvm, device);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	/*
123362306a36Sopenharmony_ci	 * The spec does not say whether unmapping a not-mapped device
123462306a36Sopenharmony_ci	 * is an error, so we are done in any case.
123562306a36Sopenharmony_ci	 */
123662306a36Sopenharmony_ci	if (!valid)
123762306a36Sopenharmony_ci		return 0;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	device = vgic_its_alloc_device(its, device_id, itt_addr,
124062306a36Sopenharmony_ci				       num_eventid_bits);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(device);
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci/*
124662306a36Sopenharmony_ci * The MAPC command maps collection IDs to redistributors.
124762306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
124862306a36Sopenharmony_ci */
124962306a36Sopenharmony_cistatic int vgic_its_cmd_handle_mapc(struct kvm *kvm, struct vgic_its *its,
125062306a36Sopenharmony_ci				    u64 *its_cmd)
125162306a36Sopenharmony_ci{
125262306a36Sopenharmony_ci	u16 coll_id;
125362306a36Sopenharmony_ci	u32 target_addr;
125462306a36Sopenharmony_ci	struct its_collection *collection;
125562306a36Sopenharmony_ci	bool valid;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	valid = its_cmd_get_validbit(its_cmd);
125862306a36Sopenharmony_ci	coll_id = its_cmd_get_collection(its_cmd);
125962306a36Sopenharmony_ci	target_addr = its_cmd_get_target_addr(its_cmd);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	if (target_addr >= atomic_read(&kvm->online_vcpus))
126262306a36Sopenharmony_ci		return E_ITS_MAPC_PROCNUM_OOR;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	if (!valid) {
126562306a36Sopenharmony_ci		vgic_its_free_collection(its, coll_id);
126662306a36Sopenharmony_ci		vgic_its_invalidate_cache(kvm);
126762306a36Sopenharmony_ci	} else {
126862306a36Sopenharmony_ci		collection = find_collection(its, coll_id);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		if (!collection) {
127162306a36Sopenharmony_ci			int ret;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci			if (!vgic_its_check_id(its, its->baser_coll_table,
127462306a36Sopenharmony_ci						coll_id, NULL))
127562306a36Sopenharmony_ci				return E_ITS_MAPC_COLLECTION_OOR;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci			ret = vgic_its_alloc_collection(its, &collection,
127862306a36Sopenharmony_ci							coll_id);
127962306a36Sopenharmony_ci			if (ret)
128062306a36Sopenharmony_ci				return ret;
128162306a36Sopenharmony_ci			collection->target_addr = target_addr;
128262306a36Sopenharmony_ci		} else {
128362306a36Sopenharmony_ci			collection->target_addr = target_addr;
128462306a36Sopenharmony_ci			update_affinity_collection(kvm, its, collection);
128562306a36Sopenharmony_ci		}
128662306a36Sopenharmony_ci	}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	return 0;
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci/*
129262306a36Sopenharmony_ci * The CLEAR command removes the pending state for a particular LPI.
129362306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
129462306a36Sopenharmony_ci */
129562306a36Sopenharmony_cistatic int vgic_its_cmd_handle_clear(struct kvm *kvm, struct vgic_its *its,
129662306a36Sopenharmony_ci				     u64 *its_cmd)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
129962306a36Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
130062306a36Sopenharmony_ci	struct its_ite *ite;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	ite = find_ite(its, device_id, event_id);
130462306a36Sopenharmony_ci	if (!ite)
130562306a36Sopenharmony_ci		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	ite->irq->pending_latch = false;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	if (ite->irq->hw)
131062306a36Sopenharmony_ci		return irq_set_irqchip_state(ite->irq->host_irq,
131162306a36Sopenharmony_ci					     IRQCHIP_STATE_PENDING, false);
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	return 0;
131462306a36Sopenharmony_ci}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ciint vgic_its_inv_lpi(struct kvm *kvm, struct vgic_irq *irq)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	return update_lpi_config(kvm, irq, NULL, true);
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci/*
132262306a36Sopenharmony_ci * The INV command syncs the configuration bits from the memory table.
132362306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
132462306a36Sopenharmony_ci */
132562306a36Sopenharmony_cistatic int vgic_its_cmd_handle_inv(struct kvm *kvm, struct vgic_its *its,
132662306a36Sopenharmony_ci				   u64 *its_cmd)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	u32 device_id = its_cmd_get_deviceid(its_cmd);
132962306a36Sopenharmony_ci	u32 event_id = its_cmd_get_id(its_cmd);
133062306a36Sopenharmony_ci	struct its_ite *ite;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	ite = find_ite(its, device_id, event_id);
133462306a36Sopenharmony_ci	if (!ite)
133562306a36Sopenharmony_ci		return E_ITS_INV_UNMAPPED_INTERRUPT;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	return vgic_its_inv_lpi(kvm, ite->irq);
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci/**
134162306a36Sopenharmony_ci * vgic_its_invall - invalidate all LPIs targetting a given vcpu
134262306a36Sopenharmony_ci * @vcpu: the vcpu for which the RD is targetted by an invalidation
134362306a36Sopenharmony_ci *
134462306a36Sopenharmony_ci * Contrary to the INVALL command, this targets a RD instead of a
134562306a36Sopenharmony_ci * collection, and we don't need to hold the its_lock, since no ITS is
134662306a36Sopenharmony_ci * involved here.
134762306a36Sopenharmony_ci */
134862306a36Sopenharmony_ciint vgic_its_invall(struct kvm_vcpu *vcpu)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	struct kvm *kvm = vcpu->kvm;
135162306a36Sopenharmony_ci	int irq_count, i = 0;
135262306a36Sopenharmony_ci	u32 *intids;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	irq_count = vgic_copy_lpi_list(kvm, vcpu, &intids);
135562306a36Sopenharmony_ci	if (irq_count < 0)
135662306a36Sopenharmony_ci		return irq_count;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	for (i = 0; i < irq_count; i++) {
135962306a36Sopenharmony_ci		struct vgic_irq *irq = vgic_get_irq(kvm, NULL, intids[i]);
136062306a36Sopenharmony_ci		if (!irq)
136162306a36Sopenharmony_ci			continue;
136262306a36Sopenharmony_ci		update_lpi_config(kvm, irq, vcpu, false);
136362306a36Sopenharmony_ci		vgic_put_irq(kvm, irq);
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	kfree(intids);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.its_vm)
136962306a36Sopenharmony_ci		its_invall_vpe(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe);
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	return 0;
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci/*
137562306a36Sopenharmony_ci * The INVALL command requests flushing of all IRQ data in this collection.
137662306a36Sopenharmony_ci * Find the VCPU mapped to that collection, then iterate over the VM's list
137762306a36Sopenharmony_ci * of mapped LPIs and update the configuration for each IRQ which targets
137862306a36Sopenharmony_ci * the specified vcpu. The configuration will be read from the in-memory
137962306a36Sopenharmony_ci * configuration table.
138062306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
138162306a36Sopenharmony_ci */
138262306a36Sopenharmony_cistatic int vgic_its_cmd_handle_invall(struct kvm *kvm, struct vgic_its *its,
138362306a36Sopenharmony_ci				      u64 *its_cmd)
138462306a36Sopenharmony_ci{
138562306a36Sopenharmony_ci	u32 coll_id = its_cmd_get_collection(its_cmd);
138662306a36Sopenharmony_ci	struct its_collection *collection;
138762306a36Sopenharmony_ci	struct kvm_vcpu *vcpu;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	collection = find_collection(its, coll_id);
139062306a36Sopenharmony_ci	if (!its_is_collection_mapped(collection))
139162306a36Sopenharmony_ci		return E_ITS_INVALL_UNMAPPED_COLLECTION;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
139462306a36Sopenharmony_ci	vgic_its_invall(vcpu);
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	return 0;
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci/*
140062306a36Sopenharmony_ci * The MOVALL command moves the pending state of all IRQs targeting one
140162306a36Sopenharmony_ci * redistributor to another. We don't hold the pending state in the VCPUs,
140262306a36Sopenharmony_ci * but in the IRQs instead, so there is really not much to do for us here.
140362306a36Sopenharmony_ci * However the spec says that no IRQ must target the old redistributor
140462306a36Sopenharmony_ci * afterwards, so we make sure that no LPI is using the associated target_vcpu.
140562306a36Sopenharmony_ci * This command affects all LPIs in the system that target that redistributor.
140662306a36Sopenharmony_ci */
140762306a36Sopenharmony_cistatic int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,
140862306a36Sopenharmony_ci				      u64 *its_cmd)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	u32 target1_addr = its_cmd_get_target_addr(its_cmd);
141162306a36Sopenharmony_ci	u32 target2_addr = its_cmd_mask_field(its_cmd, 3, 16, 32);
141262306a36Sopenharmony_ci	struct kvm_vcpu *vcpu1, *vcpu2;
141362306a36Sopenharmony_ci	struct vgic_irq *irq;
141462306a36Sopenharmony_ci	u32 *intids;
141562306a36Sopenharmony_ci	int irq_count, i;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	if (target1_addr >= atomic_read(&kvm->online_vcpus) ||
141862306a36Sopenharmony_ci	    target2_addr >= atomic_read(&kvm->online_vcpus))
141962306a36Sopenharmony_ci		return E_ITS_MOVALL_PROCNUM_OOR;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	if (target1_addr == target2_addr)
142262306a36Sopenharmony_ci		return 0;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	vcpu1 = kvm_get_vcpu(kvm, target1_addr);
142562306a36Sopenharmony_ci	vcpu2 = kvm_get_vcpu(kvm, target2_addr);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	irq_count = vgic_copy_lpi_list(kvm, vcpu1, &intids);
142862306a36Sopenharmony_ci	if (irq_count < 0)
142962306a36Sopenharmony_ci		return irq_count;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	for (i = 0; i < irq_count; i++) {
143262306a36Sopenharmony_ci		irq = vgic_get_irq(kvm, NULL, intids[i]);
143362306a36Sopenharmony_ci		if (!irq)
143462306a36Sopenharmony_ci			continue;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci		update_affinity(irq, vcpu2);
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci		vgic_put_irq(kvm, irq);
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	vgic_its_invalidate_cache(kvm);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	kfree(intids);
144462306a36Sopenharmony_ci	return 0;
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci/*
144862306a36Sopenharmony_ci * The INT command injects the LPI associated with that DevID/EvID pair.
144962306a36Sopenharmony_ci * Must be called with the its_lock mutex held.
145062306a36Sopenharmony_ci */
145162306a36Sopenharmony_cistatic int vgic_its_cmd_handle_int(struct kvm *kvm, struct vgic_its *its,
145262306a36Sopenharmony_ci				   u64 *its_cmd)
145362306a36Sopenharmony_ci{
145462306a36Sopenharmony_ci	u32 msi_data = its_cmd_get_id(its_cmd);
145562306a36Sopenharmony_ci	u64 msi_devid = its_cmd_get_deviceid(its_cmd);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	return vgic_its_trigger_msi(kvm, its, msi_devid, msi_data);
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci/*
146162306a36Sopenharmony_ci * This function is called with the its_cmd lock held, but the ITS data
146262306a36Sopenharmony_ci * structure lock dropped.
146362306a36Sopenharmony_ci */
146462306a36Sopenharmony_cistatic int vgic_its_handle_command(struct kvm *kvm, struct vgic_its *its,
146562306a36Sopenharmony_ci				   u64 *its_cmd)
146662306a36Sopenharmony_ci{
146762306a36Sopenharmony_ci	int ret = -ENODEV;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	mutex_lock(&its->its_lock);
147062306a36Sopenharmony_ci	switch (its_cmd_get_command(its_cmd)) {
147162306a36Sopenharmony_ci	case GITS_CMD_MAPD:
147262306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_mapd(kvm, its, its_cmd);
147362306a36Sopenharmony_ci		break;
147462306a36Sopenharmony_ci	case GITS_CMD_MAPC:
147562306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_mapc(kvm, its, its_cmd);
147662306a36Sopenharmony_ci		break;
147762306a36Sopenharmony_ci	case GITS_CMD_MAPI:
147862306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_mapi(kvm, its, its_cmd);
147962306a36Sopenharmony_ci		break;
148062306a36Sopenharmony_ci	case GITS_CMD_MAPTI:
148162306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_mapi(kvm, its, its_cmd);
148262306a36Sopenharmony_ci		break;
148362306a36Sopenharmony_ci	case GITS_CMD_MOVI:
148462306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_movi(kvm, its, its_cmd);
148562306a36Sopenharmony_ci		break;
148662306a36Sopenharmony_ci	case GITS_CMD_DISCARD:
148762306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_discard(kvm, its, its_cmd);
148862306a36Sopenharmony_ci		break;
148962306a36Sopenharmony_ci	case GITS_CMD_CLEAR:
149062306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_clear(kvm, its, its_cmd);
149162306a36Sopenharmony_ci		break;
149262306a36Sopenharmony_ci	case GITS_CMD_MOVALL:
149362306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_movall(kvm, its, its_cmd);
149462306a36Sopenharmony_ci		break;
149562306a36Sopenharmony_ci	case GITS_CMD_INT:
149662306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_int(kvm, its, its_cmd);
149762306a36Sopenharmony_ci		break;
149862306a36Sopenharmony_ci	case GITS_CMD_INV:
149962306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_inv(kvm, its, its_cmd);
150062306a36Sopenharmony_ci		break;
150162306a36Sopenharmony_ci	case GITS_CMD_INVALL:
150262306a36Sopenharmony_ci		ret = vgic_its_cmd_handle_invall(kvm, its, its_cmd);
150362306a36Sopenharmony_ci		break;
150462306a36Sopenharmony_ci	case GITS_CMD_SYNC:
150562306a36Sopenharmony_ci		/* we ignore this command: we are in sync all of the time */
150662306a36Sopenharmony_ci		ret = 0;
150762306a36Sopenharmony_ci		break;
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci	mutex_unlock(&its->its_lock);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	return ret;
151262306a36Sopenharmony_ci}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_cistatic u64 vgic_sanitise_its_baser(u64 reg)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_BASER_SHAREABILITY_MASK,
151762306a36Sopenharmony_ci				  GITS_BASER_SHAREABILITY_SHIFT,
151862306a36Sopenharmony_ci				  vgic_sanitise_shareability);
151962306a36Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_BASER_INNER_CACHEABILITY_MASK,
152062306a36Sopenharmony_ci				  GITS_BASER_INNER_CACHEABILITY_SHIFT,
152162306a36Sopenharmony_ci				  vgic_sanitise_inner_cacheability);
152262306a36Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_BASER_OUTER_CACHEABILITY_MASK,
152362306a36Sopenharmony_ci				  GITS_BASER_OUTER_CACHEABILITY_SHIFT,
152462306a36Sopenharmony_ci				  vgic_sanitise_outer_cacheability);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	/* We support only one (ITS) page size: 64K */
152762306a36Sopenharmony_ci	reg = (reg & ~GITS_BASER_PAGE_SIZE_MASK) | GITS_BASER_PAGE_SIZE_64K;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	return reg;
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_cistatic u64 vgic_sanitise_its_cbaser(u64 reg)
153362306a36Sopenharmony_ci{
153462306a36Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_CBASER_SHAREABILITY_MASK,
153562306a36Sopenharmony_ci				  GITS_CBASER_SHAREABILITY_SHIFT,
153662306a36Sopenharmony_ci				  vgic_sanitise_shareability);
153762306a36Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_CBASER_INNER_CACHEABILITY_MASK,
153862306a36Sopenharmony_ci				  GITS_CBASER_INNER_CACHEABILITY_SHIFT,
153962306a36Sopenharmony_ci				  vgic_sanitise_inner_cacheability);
154062306a36Sopenharmony_ci	reg = vgic_sanitise_field(reg, GITS_CBASER_OUTER_CACHEABILITY_MASK,
154162306a36Sopenharmony_ci				  GITS_CBASER_OUTER_CACHEABILITY_SHIFT,
154262306a36Sopenharmony_ci				  vgic_sanitise_outer_cacheability);
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	/* Sanitise the physical address to be 64k aligned. */
154562306a36Sopenharmony_ci	reg &= ~GENMASK_ULL(15, 12);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	return reg;
154862306a36Sopenharmony_ci}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_cistatic unsigned long vgic_mmio_read_its_cbaser(struct kvm *kvm,
155162306a36Sopenharmony_ci					       struct vgic_its *its,
155262306a36Sopenharmony_ci					       gpa_t addr, unsigned int len)
155362306a36Sopenharmony_ci{
155462306a36Sopenharmony_ci	return extract_bytes(its->cbaser, addr & 7, len);
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_cistatic void vgic_mmio_write_its_cbaser(struct kvm *kvm, struct vgic_its *its,
155862306a36Sopenharmony_ci				       gpa_t addr, unsigned int len,
155962306a36Sopenharmony_ci				       unsigned long val)
156062306a36Sopenharmony_ci{
156162306a36Sopenharmony_ci	/* When GITS_CTLR.Enable is 1, this register is RO. */
156262306a36Sopenharmony_ci	if (its->enabled)
156362306a36Sopenharmony_ci		return;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	mutex_lock(&its->cmd_lock);
156662306a36Sopenharmony_ci	its->cbaser = update_64bit_reg(its->cbaser, addr & 7, len, val);
156762306a36Sopenharmony_ci	its->cbaser = vgic_sanitise_its_cbaser(its->cbaser);
156862306a36Sopenharmony_ci	its->creadr = 0;
156962306a36Sopenharmony_ci	/*
157062306a36Sopenharmony_ci	 * CWRITER is architecturally UNKNOWN on reset, but we need to reset
157162306a36Sopenharmony_ci	 * it to CREADR to make sure we start with an empty command buffer.
157262306a36Sopenharmony_ci	 */
157362306a36Sopenharmony_ci	its->cwriter = its->creadr;
157462306a36Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
157562306a36Sopenharmony_ci}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci#define ITS_CMD_BUFFER_SIZE(baser)	((((baser) & 0xff) + 1) << 12)
157862306a36Sopenharmony_ci#define ITS_CMD_SIZE			32
157962306a36Sopenharmony_ci#define ITS_CMD_OFFSET(reg)		((reg) & GENMASK(19, 5))
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci/* Must be called with the cmd_lock held. */
158262306a36Sopenharmony_cistatic void vgic_its_process_commands(struct kvm *kvm, struct vgic_its *its)
158362306a36Sopenharmony_ci{
158462306a36Sopenharmony_ci	gpa_t cbaser;
158562306a36Sopenharmony_ci	u64 cmd_buf[4];
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	/* Commands are only processed when the ITS is enabled. */
158862306a36Sopenharmony_ci	if (!its->enabled)
158962306a36Sopenharmony_ci		return;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	cbaser = GITS_CBASER_ADDRESS(its->cbaser);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	while (its->cwriter != its->creadr) {
159462306a36Sopenharmony_ci		int ret = kvm_read_guest_lock(kvm, cbaser + its->creadr,
159562306a36Sopenharmony_ci					      cmd_buf, ITS_CMD_SIZE);
159662306a36Sopenharmony_ci		/*
159762306a36Sopenharmony_ci		 * If kvm_read_guest() fails, this could be due to the guest
159862306a36Sopenharmony_ci		 * programming a bogus value in CBASER or something else going
159962306a36Sopenharmony_ci		 * wrong from which we cannot easily recover.
160062306a36Sopenharmony_ci		 * According to section 6.3.2 in the GICv3 spec we can just
160162306a36Sopenharmony_ci		 * ignore that command then.
160262306a36Sopenharmony_ci		 */
160362306a36Sopenharmony_ci		if (!ret)
160462306a36Sopenharmony_ci			vgic_its_handle_command(kvm, its, cmd_buf);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci		its->creadr += ITS_CMD_SIZE;
160762306a36Sopenharmony_ci		if (its->creadr == ITS_CMD_BUFFER_SIZE(its->cbaser))
160862306a36Sopenharmony_ci			its->creadr = 0;
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci/*
161362306a36Sopenharmony_ci * By writing to CWRITER the guest announces new commands to be processed.
161462306a36Sopenharmony_ci * To avoid any races in the first place, we take the its_cmd lock, which
161562306a36Sopenharmony_ci * protects our ring buffer variables, so that there is only one user
161662306a36Sopenharmony_ci * per ITS handling commands at a given time.
161762306a36Sopenharmony_ci */
161862306a36Sopenharmony_cistatic void vgic_mmio_write_its_cwriter(struct kvm *kvm, struct vgic_its *its,
161962306a36Sopenharmony_ci					gpa_t addr, unsigned int len,
162062306a36Sopenharmony_ci					unsigned long val)
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	u64 reg;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	if (!its)
162562306a36Sopenharmony_ci		return;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	mutex_lock(&its->cmd_lock);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	reg = update_64bit_reg(its->cwriter, addr & 7, len, val);
163062306a36Sopenharmony_ci	reg = ITS_CMD_OFFSET(reg);
163162306a36Sopenharmony_ci	if (reg >= ITS_CMD_BUFFER_SIZE(its->cbaser)) {
163262306a36Sopenharmony_ci		mutex_unlock(&its->cmd_lock);
163362306a36Sopenharmony_ci		return;
163462306a36Sopenharmony_ci	}
163562306a36Sopenharmony_ci	its->cwriter = reg;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	vgic_its_process_commands(kvm, its);
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_cistatic unsigned long vgic_mmio_read_its_cwriter(struct kvm *kvm,
164362306a36Sopenharmony_ci						struct vgic_its *its,
164462306a36Sopenharmony_ci						gpa_t addr, unsigned int len)
164562306a36Sopenharmony_ci{
164662306a36Sopenharmony_ci	return extract_bytes(its->cwriter, addr & 0x7, len);
164762306a36Sopenharmony_ci}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_cistatic unsigned long vgic_mmio_read_its_creadr(struct kvm *kvm,
165062306a36Sopenharmony_ci					       struct vgic_its *its,
165162306a36Sopenharmony_ci					       gpa_t addr, unsigned int len)
165262306a36Sopenharmony_ci{
165362306a36Sopenharmony_ci	return extract_bytes(its->creadr, addr & 0x7, len);
165462306a36Sopenharmony_ci}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_cistatic int vgic_mmio_uaccess_write_its_creadr(struct kvm *kvm,
165762306a36Sopenharmony_ci					      struct vgic_its *its,
165862306a36Sopenharmony_ci					      gpa_t addr, unsigned int len,
165962306a36Sopenharmony_ci					      unsigned long val)
166062306a36Sopenharmony_ci{
166162306a36Sopenharmony_ci	u32 cmd_offset;
166262306a36Sopenharmony_ci	int ret = 0;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	mutex_lock(&its->cmd_lock);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	if (its->enabled) {
166762306a36Sopenharmony_ci		ret = -EBUSY;
166862306a36Sopenharmony_ci		goto out;
166962306a36Sopenharmony_ci	}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	cmd_offset = ITS_CMD_OFFSET(val);
167262306a36Sopenharmony_ci	if (cmd_offset >= ITS_CMD_BUFFER_SIZE(its->cbaser)) {
167362306a36Sopenharmony_ci		ret = -EINVAL;
167462306a36Sopenharmony_ci		goto out;
167562306a36Sopenharmony_ci	}
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	its->creadr = cmd_offset;
167862306a36Sopenharmony_ciout:
167962306a36Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
168062306a36Sopenharmony_ci	return ret;
168162306a36Sopenharmony_ci}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci#define BASER_INDEX(addr) (((addr) / sizeof(u64)) & 0x7)
168462306a36Sopenharmony_cistatic unsigned long vgic_mmio_read_its_baser(struct kvm *kvm,
168562306a36Sopenharmony_ci					      struct vgic_its *its,
168662306a36Sopenharmony_ci					      gpa_t addr, unsigned int len)
168762306a36Sopenharmony_ci{
168862306a36Sopenharmony_ci	u64 reg;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	switch (BASER_INDEX(addr)) {
169162306a36Sopenharmony_ci	case 0:
169262306a36Sopenharmony_ci		reg = its->baser_device_table;
169362306a36Sopenharmony_ci		break;
169462306a36Sopenharmony_ci	case 1:
169562306a36Sopenharmony_ci		reg = its->baser_coll_table;
169662306a36Sopenharmony_ci		break;
169762306a36Sopenharmony_ci	default:
169862306a36Sopenharmony_ci		reg = 0;
169962306a36Sopenharmony_ci		break;
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	return extract_bytes(reg, addr & 7, len);
170362306a36Sopenharmony_ci}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci#define GITS_BASER_RO_MASK	(GENMASK_ULL(52, 48) | GENMASK_ULL(58, 56))
170662306a36Sopenharmony_cistatic void vgic_mmio_write_its_baser(struct kvm *kvm,
170762306a36Sopenharmony_ci				      struct vgic_its *its,
170862306a36Sopenharmony_ci				      gpa_t addr, unsigned int len,
170962306a36Sopenharmony_ci				      unsigned long val)
171062306a36Sopenharmony_ci{
171162306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
171262306a36Sopenharmony_ci	u64 entry_size, table_type;
171362306a36Sopenharmony_ci	u64 reg, *regptr, clearbits = 0;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	/* When GITS_CTLR.Enable is 1, we ignore write accesses. */
171662306a36Sopenharmony_ci	if (its->enabled)
171762306a36Sopenharmony_ci		return;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	switch (BASER_INDEX(addr)) {
172062306a36Sopenharmony_ci	case 0:
172162306a36Sopenharmony_ci		regptr = &its->baser_device_table;
172262306a36Sopenharmony_ci		entry_size = abi->dte_esz;
172362306a36Sopenharmony_ci		table_type = GITS_BASER_TYPE_DEVICE;
172462306a36Sopenharmony_ci		break;
172562306a36Sopenharmony_ci	case 1:
172662306a36Sopenharmony_ci		regptr = &its->baser_coll_table;
172762306a36Sopenharmony_ci		entry_size = abi->cte_esz;
172862306a36Sopenharmony_ci		table_type = GITS_BASER_TYPE_COLLECTION;
172962306a36Sopenharmony_ci		clearbits = GITS_BASER_INDIRECT;
173062306a36Sopenharmony_ci		break;
173162306a36Sopenharmony_ci	default:
173262306a36Sopenharmony_ci		return;
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	reg = update_64bit_reg(*regptr, addr & 7, len, val);
173662306a36Sopenharmony_ci	reg &= ~GITS_BASER_RO_MASK;
173762306a36Sopenharmony_ci	reg &= ~clearbits;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	reg |= (entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT;
174062306a36Sopenharmony_ci	reg |= table_type << GITS_BASER_TYPE_SHIFT;
174162306a36Sopenharmony_ci	reg = vgic_sanitise_its_baser(reg);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	*regptr = reg;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	if (!(reg & GITS_BASER_VALID)) {
174662306a36Sopenharmony_ci		/* Take the its_lock to prevent a race with a save/restore */
174762306a36Sopenharmony_ci		mutex_lock(&its->its_lock);
174862306a36Sopenharmony_ci		switch (table_type) {
174962306a36Sopenharmony_ci		case GITS_BASER_TYPE_DEVICE:
175062306a36Sopenharmony_ci			vgic_its_free_device_list(kvm, its);
175162306a36Sopenharmony_ci			break;
175262306a36Sopenharmony_ci		case GITS_BASER_TYPE_COLLECTION:
175362306a36Sopenharmony_ci			vgic_its_free_collection_list(kvm, its);
175462306a36Sopenharmony_ci			break;
175562306a36Sopenharmony_ci		}
175662306a36Sopenharmony_ci		mutex_unlock(&its->its_lock);
175762306a36Sopenharmony_ci	}
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_cistatic unsigned long vgic_mmio_read_its_ctlr(struct kvm *vcpu,
176162306a36Sopenharmony_ci					     struct vgic_its *its,
176262306a36Sopenharmony_ci					     gpa_t addr, unsigned int len)
176362306a36Sopenharmony_ci{
176462306a36Sopenharmony_ci	u32 reg = 0;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	mutex_lock(&its->cmd_lock);
176762306a36Sopenharmony_ci	if (its->creadr == its->cwriter)
176862306a36Sopenharmony_ci		reg |= GITS_CTLR_QUIESCENT;
176962306a36Sopenharmony_ci	if (its->enabled)
177062306a36Sopenharmony_ci		reg |= GITS_CTLR_ENABLE;
177162306a36Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	return reg;
177462306a36Sopenharmony_ci}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_cistatic void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
177762306a36Sopenharmony_ci				     gpa_t addr, unsigned int len,
177862306a36Sopenharmony_ci				     unsigned long val)
177962306a36Sopenharmony_ci{
178062306a36Sopenharmony_ci	mutex_lock(&its->cmd_lock);
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	/*
178362306a36Sopenharmony_ci	 * It is UNPREDICTABLE to enable the ITS if any of the CBASER or
178462306a36Sopenharmony_ci	 * device/collection BASER are invalid
178562306a36Sopenharmony_ci	 */
178662306a36Sopenharmony_ci	if (!its->enabled && (val & GITS_CTLR_ENABLE) &&
178762306a36Sopenharmony_ci		(!(its->baser_device_table & GITS_BASER_VALID) ||
178862306a36Sopenharmony_ci		 !(its->baser_coll_table & GITS_BASER_VALID) ||
178962306a36Sopenharmony_ci		 !(its->cbaser & GITS_CBASER_VALID)))
179062306a36Sopenharmony_ci		goto out;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	its->enabled = !!(val & GITS_CTLR_ENABLE);
179362306a36Sopenharmony_ci	if (!its->enabled)
179462306a36Sopenharmony_ci		vgic_its_invalidate_cache(kvm);
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	/*
179762306a36Sopenharmony_ci	 * Try to process any pending commands. This function bails out early
179862306a36Sopenharmony_ci	 * if the ITS is disabled or no commands have been queued.
179962306a36Sopenharmony_ci	 */
180062306a36Sopenharmony_ci	vgic_its_process_commands(kvm, its);
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ciout:
180362306a36Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
180462306a36Sopenharmony_ci}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci#define REGISTER_ITS_DESC(off, rd, wr, length, acc)		\
180762306a36Sopenharmony_ci{								\
180862306a36Sopenharmony_ci	.reg_offset = off,					\
180962306a36Sopenharmony_ci	.len = length,						\
181062306a36Sopenharmony_ci	.access_flags = acc,					\
181162306a36Sopenharmony_ci	.its_read = rd,						\
181262306a36Sopenharmony_ci	.its_write = wr,					\
181362306a36Sopenharmony_ci}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci#define REGISTER_ITS_DESC_UACCESS(off, rd, wr, uwr, length, acc)\
181662306a36Sopenharmony_ci{								\
181762306a36Sopenharmony_ci	.reg_offset = off,					\
181862306a36Sopenharmony_ci	.len = length,						\
181962306a36Sopenharmony_ci	.access_flags = acc,					\
182062306a36Sopenharmony_ci	.its_read = rd,						\
182162306a36Sopenharmony_ci	.its_write = wr,					\
182262306a36Sopenharmony_ci	.uaccess_its_write = uwr,				\
182362306a36Sopenharmony_ci}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_cistatic void its_mmio_write_wi(struct kvm *kvm, struct vgic_its *its,
182662306a36Sopenharmony_ci			      gpa_t addr, unsigned int len, unsigned long val)
182762306a36Sopenharmony_ci{
182862306a36Sopenharmony_ci	/* Ignore */
182962306a36Sopenharmony_ci}
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_cistatic struct vgic_register_region its_registers[] = {
183262306a36Sopenharmony_ci	REGISTER_ITS_DESC(GITS_CTLR,
183362306a36Sopenharmony_ci		vgic_mmio_read_its_ctlr, vgic_mmio_write_its_ctlr, 4,
183462306a36Sopenharmony_ci		VGIC_ACCESS_32bit),
183562306a36Sopenharmony_ci	REGISTER_ITS_DESC_UACCESS(GITS_IIDR,
183662306a36Sopenharmony_ci		vgic_mmio_read_its_iidr, its_mmio_write_wi,
183762306a36Sopenharmony_ci		vgic_mmio_uaccess_write_its_iidr, 4,
183862306a36Sopenharmony_ci		VGIC_ACCESS_32bit),
183962306a36Sopenharmony_ci	REGISTER_ITS_DESC(GITS_TYPER,
184062306a36Sopenharmony_ci		vgic_mmio_read_its_typer, its_mmio_write_wi, 8,
184162306a36Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
184262306a36Sopenharmony_ci	REGISTER_ITS_DESC(GITS_CBASER,
184362306a36Sopenharmony_ci		vgic_mmio_read_its_cbaser, vgic_mmio_write_its_cbaser, 8,
184462306a36Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
184562306a36Sopenharmony_ci	REGISTER_ITS_DESC(GITS_CWRITER,
184662306a36Sopenharmony_ci		vgic_mmio_read_its_cwriter, vgic_mmio_write_its_cwriter, 8,
184762306a36Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
184862306a36Sopenharmony_ci	REGISTER_ITS_DESC_UACCESS(GITS_CREADR,
184962306a36Sopenharmony_ci		vgic_mmio_read_its_creadr, its_mmio_write_wi,
185062306a36Sopenharmony_ci		vgic_mmio_uaccess_write_its_creadr, 8,
185162306a36Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
185262306a36Sopenharmony_ci	REGISTER_ITS_DESC(GITS_BASER,
185362306a36Sopenharmony_ci		vgic_mmio_read_its_baser, vgic_mmio_write_its_baser, 0x40,
185462306a36Sopenharmony_ci		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
185562306a36Sopenharmony_ci	REGISTER_ITS_DESC(GITS_IDREGS_BASE,
185662306a36Sopenharmony_ci		vgic_mmio_read_its_idregs, its_mmio_write_wi, 0x30,
185762306a36Sopenharmony_ci		VGIC_ACCESS_32bit),
185862306a36Sopenharmony_ci};
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci/* This is called on setting the LPI enable bit in the redistributor. */
186162306a36Sopenharmony_civoid vgic_enable_lpis(struct kvm_vcpu *vcpu)
186262306a36Sopenharmony_ci{
186362306a36Sopenharmony_ci	if (!(vcpu->arch.vgic_cpu.pendbaser & GICR_PENDBASER_PTZ))
186462306a36Sopenharmony_ci		its_sync_lpi_pending_table(vcpu);
186562306a36Sopenharmony_ci}
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_cistatic int vgic_register_its_iodev(struct kvm *kvm, struct vgic_its *its,
186862306a36Sopenharmony_ci				   u64 addr)
186962306a36Sopenharmony_ci{
187062306a36Sopenharmony_ci	struct vgic_io_device *iodev = &its->iodev;
187162306a36Sopenharmony_ci	int ret;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	mutex_lock(&kvm->slots_lock);
187462306a36Sopenharmony_ci	if (!IS_VGIC_ADDR_UNDEF(its->vgic_its_base)) {
187562306a36Sopenharmony_ci		ret = -EBUSY;
187662306a36Sopenharmony_ci		goto out;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	its->vgic_its_base = addr;
188062306a36Sopenharmony_ci	iodev->regions = its_registers;
188162306a36Sopenharmony_ci	iodev->nr_regions = ARRAY_SIZE(its_registers);
188262306a36Sopenharmony_ci	kvm_iodevice_init(&iodev->dev, &kvm_io_gic_ops);
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	iodev->base_addr = its->vgic_its_base;
188562306a36Sopenharmony_ci	iodev->iodev_type = IODEV_ITS;
188662306a36Sopenharmony_ci	iodev->its = its;
188762306a36Sopenharmony_ci	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, iodev->base_addr,
188862306a36Sopenharmony_ci				      KVM_VGIC_V3_ITS_SIZE, &iodev->dev);
188962306a36Sopenharmony_ciout:
189062306a36Sopenharmony_ci	mutex_unlock(&kvm->slots_lock);
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	return ret;
189362306a36Sopenharmony_ci}
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci/* Default is 16 cached LPIs per vcpu */
189662306a36Sopenharmony_ci#define LPI_DEFAULT_PCPU_CACHE_SIZE	16
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_civoid vgic_lpi_translation_cache_init(struct kvm *kvm)
189962306a36Sopenharmony_ci{
190062306a36Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
190162306a36Sopenharmony_ci	unsigned int sz;
190262306a36Sopenharmony_ci	int i;
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	if (!list_empty(&dist->lpi_translation_cache))
190562306a36Sopenharmony_ci		return;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	sz = atomic_read(&kvm->online_vcpus) * LPI_DEFAULT_PCPU_CACHE_SIZE;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	for (i = 0; i < sz; i++) {
191062306a36Sopenharmony_ci		struct vgic_translation_cache_entry *cte;
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci		/* An allocation failure is not fatal */
191362306a36Sopenharmony_ci		cte = kzalloc(sizeof(*cte), GFP_KERNEL_ACCOUNT);
191462306a36Sopenharmony_ci		if (WARN_ON(!cte))
191562306a36Sopenharmony_ci			break;
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci		INIT_LIST_HEAD(&cte->entry);
191862306a36Sopenharmony_ci		list_add(&cte->entry, &dist->lpi_translation_cache);
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_civoid vgic_lpi_translation_cache_destroy(struct kvm *kvm)
192362306a36Sopenharmony_ci{
192462306a36Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
192562306a36Sopenharmony_ci	struct vgic_translation_cache_entry *cte, *tmp;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	vgic_its_invalidate_cache(kvm);
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	list_for_each_entry_safe(cte, tmp,
193062306a36Sopenharmony_ci				 &dist->lpi_translation_cache, entry) {
193162306a36Sopenharmony_ci		list_del(&cte->entry);
193262306a36Sopenharmony_ci		kfree(cte);
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci#define INITIAL_BASER_VALUE						  \
193762306a36Sopenharmony_ci	(GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb)		| \
193862306a36Sopenharmony_ci	 GIC_BASER_CACHEABILITY(GITS_BASER, OUTER, SameAsInner)		| \
193962306a36Sopenharmony_ci	 GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)		| \
194062306a36Sopenharmony_ci	 GITS_BASER_PAGE_SIZE_64K)
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci#define INITIAL_PROPBASER_VALUE						  \
194362306a36Sopenharmony_ci	(GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWb)		| \
194462306a36Sopenharmony_ci	 GIC_BASER_CACHEABILITY(GICR_PROPBASER, OUTER, SameAsInner)	| \
194562306a36Sopenharmony_ci	 GIC_BASER_SHAREABILITY(GICR_PROPBASER, InnerShareable))
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_cistatic int vgic_its_create(struct kvm_device *dev, u32 type)
194862306a36Sopenharmony_ci{
194962306a36Sopenharmony_ci	int ret;
195062306a36Sopenharmony_ci	struct vgic_its *its;
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	if (type != KVM_DEV_TYPE_ARM_VGIC_ITS)
195362306a36Sopenharmony_ci		return -ENODEV;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	its = kzalloc(sizeof(struct vgic_its), GFP_KERNEL_ACCOUNT);
195662306a36Sopenharmony_ci	if (!its)
195762306a36Sopenharmony_ci		return -ENOMEM;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	mutex_lock(&dev->kvm->arch.config_lock);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	if (vgic_initialized(dev->kvm)) {
196262306a36Sopenharmony_ci		ret = vgic_v4_init(dev->kvm);
196362306a36Sopenharmony_ci		if (ret < 0) {
196462306a36Sopenharmony_ci			mutex_unlock(&dev->kvm->arch.config_lock);
196562306a36Sopenharmony_ci			kfree(its);
196662306a36Sopenharmony_ci			return ret;
196762306a36Sopenharmony_ci		}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci		vgic_lpi_translation_cache_init(dev->kvm);
197062306a36Sopenharmony_ci	}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	mutex_init(&its->its_lock);
197362306a36Sopenharmony_ci	mutex_init(&its->cmd_lock);
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	/* Yep, even more trickery for lock ordering... */
197662306a36Sopenharmony_ci#ifdef CONFIG_LOCKDEP
197762306a36Sopenharmony_ci	mutex_lock(&its->cmd_lock);
197862306a36Sopenharmony_ci	mutex_lock(&its->its_lock);
197962306a36Sopenharmony_ci	mutex_unlock(&its->its_lock);
198062306a36Sopenharmony_ci	mutex_unlock(&its->cmd_lock);
198162306a36Sopenharmony_ci#endif
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	its->vgic_its_base = VGIC_ADDR_UNDEF;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	INIT_LIST_HEAD(&its->device_list);
198662306a36Sopenharmony_ci	INIT_LIST_HEAD(&its->collection_list);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	dev->kvm->arch.vgic.msis_require_devid = true;
198962306a36Sopenharmony_ci	dev->kvm->arch.vgic.has_its = true;
199062306a36Sopenharmony_ci	its->enabled = false;
199162306a36Sopenharmony_ci	its->dev = dev;
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	its->baser_device_table = INITIAL_BASER_VALUE			|
199462306a36Sopenharmony_ci		((u64)GITS_BASER_TYPE_DEVICE << GITS_BASER_TYPE_SHIFT);
199562306a36Sopenharmony_ci	its->baser_coll_table = INITIAL_BASER_VALUE |
199662306a36Sopenharmony_ci		((u64)GITS_BASER_TYPE_COLLECTION << GITS_BASER_TYPE_SHIFT);
199762306a36Sopenharmony_ci	dev->kvm->arch.vgic.propbaser = INITIAL_PROPBASER_VALUE;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	dev->private = its;
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	ret = vgic_its_set_abi(its, NR_ITS_ABIS - 1);
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	mutex_unlock(&dev->kvm->arch.config_lock);
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	return ret;
200662306a36Sopenharmony_ci}
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_cistatic void vgic_its_destroy(struct kvm_device *kvm_dev)
200962306a36Sopenharmony_ci{
201062306a36Sopenharmony_ci	struct kvm *kvm = kvm_dev->kvm;
201162306a36Sopenharmony_ci	struct vgic_its *its = kvm_dev->private;
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	mutex_lock(&its->its_lock);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	vgic_its_free_device_list(kvm, its);
201662306a36Sopenharmony_ci	vgic_its_free_collection_list(kvm, its);
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	mutex_unlock(&its->its_lock);
201962306a36Sopenharmony_ci	kfree(its);
202062306a36Sopenharmony_ci	kfree(kvm_dev);/* alloc by kvm_ioctl_create_device, free by .destroy */
202162306a36Sopenharmony_ci}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_cistatic int vgic_its_has_attr_regs(struct kvm_device *dev,
202462306a36Sopenharmony_ci				  struct kvm_device_attr *attr)
202562306a36Sopenharmony_ci{
202662306a36Sopenharmony_ci	const struct vgic_register_region *region;
202762306a36Sopenharmony_ci	gpa_t offset = attr->attr;
202862306a36Sopenharmony_ci	int align;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	align = (offset < GITS_TYPER) || (offset >= GITS_PIDR4) ? 0x3 : 0x7;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	if (offset & align)
203362306a36Sopenharmony_ci		return -EINVAL;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	region = vgic_find_mmio_region(its_registers,
203662306a36Sopenharmony_ci				       ARRAY_SIZE(its_registers),
203762306a36Sopenharmony_ci				       offset);
203862306a36Sopenharmony_ci	if (!region)
203962306a36Sopenharmony_ci		return -ENXIO;
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	return 0;
204262306a36Sopenharmony_ci}
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_cistatic int vgic_its_attr_regs_access(struct kvm_device *dev,
204562306a36Sopenharmony_ci				     struct kvm_device_attr *attr,
204662306a36Sopenharmony_ci				     u64 *reg, bool is_write)
204762306a36Sopenharmony_ci{
204862306a36Sopenharmony_ci	const struct vgic_register_region *region;
204962306a36Sopenharmony_ci	struct vgic_its *its;
205062306a36Sopenharmony_ci	gpa_t addr, offset;
205162306a36Sopenharmony_ci	unsigned int len;
205262306a36Sopenharmony_ci	int align, ret = 0;
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	its = dev->private;
205562306a36Sopenharmony_ci	offset = attr->attr;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/*
205862306a36Sopenharmony_ci	 * Although the spec supports upper/lower 32-bit accesses to
205962306a36Sopenharmony_ci	 * 64-bit ITS registers, the userspace ABI requires 64-bit
206062306a36Sopenharmony_ci	 * accesses to all 64-bit wide registers. We therefore only
206162306a36Sopenharmony_ci	 * support 32-bit accesses to GITS_CTLR, GITS_IIDR and GITS ID
206262306a36Sopenharmony_ci	 * registers
206362306a36Sopenharmony_ci	 */
206462306a36Sopenharmony_ci	if ((offset < GITS_TYPER) || (offset >= GITS_PIDR4))
206562306a36Sopenharmony_ci		align = 0x3;
206662306a36Sopenharmony_ci	else
206762306a36Sopenharmony_ci		align = 0x7;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	if (offset & align)
207062306a36Sopenharmony_ci		return -EINVAL;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	mutex_lock(&dev->kvm->lock);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	if (!lock_all_vcpus(dev->kvm)) {
207562306a36Sopenharmony_ci		mutex_unlock(&dev->kvm->lock);
207662306a36Sopenharmony_ci		return -EBUSY;
207762306a36Sopenharmony_ci	}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	mutex_lock(&dev->kvm->arch.config_lock);
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base)) {
208262306a36Sopenharmony_ci		ret = -ENXIO;
208362306a36Sopenharmony_ci		goto out;
208462306a36Sopenharmony_ci	}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	region = vgic_find_mmio_region(its_registers,
208762306a36Sopenharmony_ci				       ARRAY_SIZE(its_registers),
208862306a36Sopenharmony_ci				       offset);
208962306a36Sopenharmony_ci	if (!region) {
209062306a36Sopenharmony_ci		ret = -ENXIO;
209162306a36Sopenharmony_ci		goto out;
209262306a36Sopenharmony_ci	}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	addr = its->vgic_its_base + offset;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	len = region->access_flags & VGIC_ACCESS_64bit ? 8 : 4;
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	if (is_write) {
209962306a36Sopenharmony_ci		if (region->uaccess_its_write)
210062306a36Sopenharmony_ci			ret = region->uaccess_its_write(dev->kvm, its, addr,
210162306a36Sopenharmony_ci							len, *reg);
210262306a36Sopenharmony_ci		else
210362306a36Sopenharmony_ci			region->its_write(dev->kvm, its, addr, len, *reg);
210462306a36Sopenharmony_ci	} else {
210562306a36Sopenharmony_ci		*reg = region->its_read(dev->kvm, its, addr, len);
210662306a36Sopenharmony_ci	}
210762306a36Sopenharmony_ciout:
210862306a36Sopenharmony_ci	mutex_unlock(&dev->kvm->arch.config_lock);
210962306a36Sopenharmony_ci	unlock_all_vcpus(dev->kvm);
211062306a36Sopenharmony_ci	mutex_unlock(&dev->kvm->lock);
211162306a36Sopenharmony_ci	return ret;
211262306a36Sopenharmony_ci}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_cistatic u32 compute_next_devid_offset(struct list_head *h,
211562306a36Sopenharmony_ci				     struct its_device *dev)
211662306a36Sopenharmony_ci{
211762306a36Sopenharmony_ci	struct its_device *next;
211862306a36Sopenharmony_ci	u32 next_offset;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	if (list_is_last(&dev->dev_list, h))
212162306a36Sopenharmony_ci		return 0;
212262306a36Sopenharmony_ci	next = list_next_entry(dev, dev_list);
212362306a36Sopenharmony_ci	next_offset = next->device_id - dev->device_id;
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
212662306a36Sopenharmony_ci}
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_cistatic u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
212962306a36Sopenharmony_ci{
213062306a36Sopenharmony_ci	struct its_ite *next;
213162306a36Sopenharmony_ci	u32 next_offset;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	if (list_is_last(&ite->ite_list, h))
213462306a36Sopenharmony_ci		return 0;
213562306a36Sopenharmony_ci	next = list_next_entry(ite, ite_list);
213662306a36Sopenharmony_ci	next_offset = next->event_id - ite->event_id;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	return min_t(u32, next_offset, VITS_ITE_MAX_EVENTID_OFFSET);
213962306a36Sopenharmony_ci}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci/**
214262306a36Sopenharmony_ci * entry_fn_t - Callback called on a table entry restore path
214362306a36Sopenharmony_ci * @its: its handle
214462306a36Sopenharmony_ci * @id: id of the entry
214562306a36Sopenharmony_ci * @entry: pointer to the entry
214662306a36Sopenharmony_ci * @opaque: pointer to an opaque data
214762306a36Sopenharmony_ci *
214862306a36Sopenharmony_ci * Return: < 0 on error, 0 if last element was identified, id offset to next
214962306a36Sopenharmony_ci * element otherwise
215062306a36Sopenharmony_ci */
215162306a36Sopenharmony_citypedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
215262306a36Sopenharmony_ci			  void *opaque);
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci/**
215562306a36Sopenharmony_ci * scan_its_table - Scan a contiguous table in guest RAM and applies a function
215662306a36Sopenharmony_ci * to each entry
215762306a36Sopenharmony_ci *
215862306a36Sopenharmony_ci * @its: its handle
215962306a36Sopenharmony_ci * @base: base gpa of the table
216062306a36Sopenharmony_ci * @size: size of the table in bytes
216162306a36Sopenharmony_ci * @esz: entry size in bytes
216262306a36Sopenharmony_ci * @start_id: the ID of the first entry in the table
216362306a36Sopenharmony_ci * (non zero for 2d level tables)
216462306a36Sopenharmony_ci * @fn: function to apply on each entry
216562306a36Sopenharmony_ci *
216662306a36Sopenharmony_ci * Return: < 0 on error, 0 if last element was identified, 1 otherwise
216762306a36Sopenharmony_ci * (the last element may not be found on second level tables)
216862306a36Sopenharmony_ci */
216962306a36Sopenharmony_cistatic int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
217062306a36Sopenharmony_ci			  int start_id, entry_fn_t fn, void *opaque)
217162306a36Sopenharmony_ci{
217262306a36Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
217362306a36Sopenharmony_ci	unsigned long len = size;
217462306a36Sopenharmony_ci	int id = start_id;
217562306a36Sopenharmony_ci	gpa_t gpa = base;
217662306a36Sopenharmony_ci	char entry[ESZ_MAX];
217762306a36Sopenharmony_ci	int ret;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	memset(entry, 0, esz);
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	while (true) {
218262306a36Sopenharmony_ci		int next_offset;
218362306a36Sopenharmony_ci		size_t byte_offset;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci		ret = kvm_read_guest_lock(kvm, gpa, entry, esz);
218662306a36Sopenharmony_ci		if (ret)
218762306a36Sopenharmony_ci			return ret;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci		next_offset = fn(its, id, entry, opaque);
219062306a36Sopenharmony_ci		if (next_offset <= 0)
219162306a36Sopenharmony_ci			return next_offset;
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci		byte_offset = next_offset * esz;
219462306a36Sopenharmony_ci		if (byte_offset >= len)
219562306a36Sopenharmony_ci			break;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci		id += next_offset;
219862306a36Sopenharmony_ci		gpa += byte_offset;
219962306a36Sopenharmony_ci		len -= byte_offset;
220062306a36Sopenharmony_ci	}
220162306a36Sopenharmony_ci	return 1;
220262306a36Sopenharmony_ci}
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci/**
220562306a36Sopenharmony_ci * vgic_its_save_ite - Save an interrupt translation entry at @gpa
220662306a36Sopenharmony_ci */
220762306a36Sopenharmony_cistatic int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
220862306a36Sopenharmony_ci			      struct its_ite *ite, gpa_t gpa, int ite_esz)
220962306a36Sopenharmony_ci{
221062306a36Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
221162306a36Sopenharmony_ci	u32 next_offset;
221262306a36Sopenharmony_ci	u64 val;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
221562306a36Sopenharmony_ci	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
221662306a36Sopenharmony_ci	       ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
221762306a36Sopenharmony_ci		ite->collection->collection_id;
221862306a36Sopenharmony_ci	val = cpu_to_le64(val);
221962306a36Sopenharmony_ci	return vgic_write_guest_lock(kvm, gpa, &val, ite_esz);
222062306a36Sopenharmony_ci}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci/**
222362306a36Sopenharmony_ci * vgic_its_restore_ite - restore an interrupt translation entry
222462306a36Sopenharmony_ci * @event_id: id used for indexing
222562306a36Sopenharmony_ci * @ptr: pointer to the ITE entry
222662306a36Sopenharmony_ci * @opaque: pointer to the its_device
222762306a36Sopenharmony_ci */
222862306a36Sopenharmony_cistatic int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
222962306a36Sopenharmony_ci				void *ptr, void *opaque)
223062306a36Sopenharmony_ci{
223162306a36Sopenharmony_ci	struct its_device *dev = opaque;
223262306a36Sopenharmony_ci	struct its_collection *collection;
223362306a36Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
223462306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = NULL;
223562306a36Sopenharmony_ci	u64 val;
223662306a36Sopenharmony_ci	u64 *p = (u64 *)ptr;
223762306a36Sopenharmony_ci	struct vgic_irq *irq;
223862306a36Sopenharmony_ci	u32 coll_id, lpi_id;
223962306a36Sopenharmony_ci	struct its_ite *ite;
224062306a36Sopenharmony_ci	u32 offset;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	val = *p;
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	val = le64_to_cpu(val);
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	coll_id = val & KVM_ITS_ITE_ICID_MASK;
224762306a36Sopenharmony_ci	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	if (!lpi_id)
225062306a36Sopenharmony_ci		return 1; /* invalid entry, no choice but to scan next entry */
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	if (lpi_id < VGIC_MIN_LPI)
225362306a36Sopenharmony_ci		return -EINVAL;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
225662306a36Sopenharmony_ci	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
225762306a36Sopenharmony_ci		return -EINVAL;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	collection = find_collection(its, coll_id);
226062306a36Sopenharmony_ci	if (!collection)
226162306a36Sopenharmony_ci		return -EINVAL;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	if (!vgic_its_check_event_id(its, dev, event_id))
226462306a36Sopenharmony_ci		return -EINVAL;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	ite = vgic_its_alloc_ite(dev, collection, event_id);
226762306a36Sopenharmony_ci	if (IS_ERR(ite))
226862306a36Sopenharmony_ci		return PTR_ERR(ite);
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	if (its_is_collection_mapped(collection))
227162306a36Sopenharmony_ci		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
227462306a36Sopenharmony_ci	if (IS_ERR(irq)) {
227562306a36Sopenharmony_ci		its_free_ite(kvm, ite);
227662306a36Sopenharmony_ci		return PTR_ERR(irq);
227762306a36Sopenharmony_ci	}
227862306a36Sopenharmony_ci	ite->irq = irq;
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	return offset;
228162306a36Sopenharmony_ci}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_cistatic int vgic_its_ite_cmp(void *priv, const struct list_head *a,
228462306a36Sopenharmony_ci			    const struct list_head *b)
228562306a36Sopenharmony_ci{
228662306a36Sopenharmony_ci	struct its_ite *itea = container_of(a, struct its_ite, ite_list);
228762306a36Sopenharmony_ci	struct its_ite *iteb = container_of(b, struct its_ite, ite_list);
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	if (itea->event_id < iteb->event_id)
229062306a36Sopenharmony_ci		return -1;
229162306a36Sopenharmony_ci	else
229262306a36Sopenharmony_ci		return 1;
229362306a36Sopenharmony_ci}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_cistatic int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
229662306a36Sopenharmony_ci{
229762306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
229862306a36Sopenharmony_ci	gpa_t base = device->itt_addr;
229962306a36Sopenharmony_ci	struct its_ite *ite;
230062306a36Sopenharmony_ci	int ret;
230162306a36Sopenharmony_ci	int ite_esz = abi->ite_esz;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	list_sort(NULL, &device->itt_head, vgic_its_ite_cmp);
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	list_for_each_entry(ite, &device->itt_head, ite_list) {
230662306a36Sopenharmony_ci		gpa_t gpa = base + ite->event_id * ite_esz;
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci		/*
230962306a36Sopenharmony_ci		 * If an LPI carries the HW bit, this means that this
231062306a36Sopenharmony_ci		 * interrupt is controlled by GICv4, and we do not
231162306a36Sopenharmony_ci		 * have direct access to that state without GICv4.1.
231262306a36Sopenharmony_ci		 * Let's simply fail the save operation...
231362306a36Sopenharmony_ci		 */
231462306a36Sopenharmony_ci		if (ite->irq->hw && !kvm_vgic_global_state.has_gicv4_1)
231562306a36Sopenharmony_ci			return -EACCES;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci		ret = vgic_its_save_ite(its, device, ite, gpa, ite_esz);
231862306a36Sopenharmony_ci		if (ret)
231962306a36Sopenharmony_ci			return ret;
232062306a36Sopenharmony_ci	}
232162306a36Sopenharmony_ci	return 0;
232262306a36Sopenharmony_ci}
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci/**
232562306a36Sopenharmony_ci * vgic_its_restore_itt - restore the ITT of a device
232662306a36Sopenharmony_ci *
232762306a36Sopenharmony_ci * @its: its handle
232862306a36Sopenharmony_ci * @dev: device handle
232962306a36Sopenharmony_ci *
233062306a36Sopenharmony_ci * Return 0 on success, < 0 on error
233162306a36Sopenharmony_ci */
233262306a36Sopenharmony_cistatic int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
233362306a36Sopenharmony_ci{
233462306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
233562306a36Sopenharmony_ci	gpa_t base = dev->itt_addr;
233662306a36Sopenharmony_ci	int ret;
233762306a36Sopenharmony_ci	int ite_esz = abi->ite_esz;
233862306a36Sopenharmony_ci	size_t max_size = BIT_ULL(dev->num_eventid_bits) * ite_esz;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	ret = scan_its_table(its, base, max_size, ite_esz, 0,
234162306a36Sopenharmony_ci			     vgic_its_restore_ite, dev);
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	/* scan_its_table returns +1 if all ITEs are invalid */
234462306a36Sopenharmony_ci	if (ret > 0)
234562306a36Sopenharmony_ci		ret = 0;
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	return ret;
234862306a36Sopenharmony_ci}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci/**
235162306a36Sopenharmony_ci * vgic_its_save_dte - Save a device table entry at a given GPA
235262306a36Sopenharmony_ci *
235362306a36Sopenharmony_ci * @its: ITS handle
235462306a36Sopenharmony_ci * @dev: ITS device
235562306a36Sopenharmony_ci * @ptr: GPA
235662306a36Sopenharmony_ci */
235762306a36Sopenharmony_cistatic int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
235862306a36Sopenharmony_ci			     gpa_t ptr, int dte_esz)
235962306a36Sopenharmony_ci{
236062306a36Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
236162306a36Sopenharmony_ci	u64 val, itt_addr_field;
236262306a36Sopenharmony_ci	u32 next_offset;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	itt_addr_field = dev->itt_addr >> 8;
236562306a36Sopenharmony_ci	next_offset = compute_next_devid_offset(&its->device_list, dev);
236662306a36Sopenharmony_ci	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
236762306a36Sopenharmony_ci	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
236862306a36Sopenharmony_ci	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
236962306a36Sopenharmony_ci		(dev->num_eventid_bits - 1));
237062306a36Sopenharmony_ci	val = cpu_to_le64(val);
237162306a36Sopenharmony_ci	return vgic_write_guest_lock(kvm, ptr, &val, dte_esz);
237262306a36Sopenharmony_ci}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci/**
237562306a36Sopenharmony_ci * vgic_its_restore_dte - restore a device table entry
237662306a36Sopenharmony_ci *
237762306a36Sopenharmony_ci * @its: its handle
237862306a36Sopenharmony_ci * @id: device id the DTE corresponds to
237962306a36Sopenharmony_ci * @ptr: kernel VA where the 8 byte DTE is located
238062306a36Sopenharmony_ci * @opaque: unused
238162306a36Sopenharmony_ci *
238262306a36Sopenharmony_ci * Return: < 0 on error, 0 if the dte is the last one, id offset to the
238362306a36Sopenharmony_ci * next dte otherwise
238462306a36Sopenharmony_ci */
238562306a36Sopenharmony_cistatic int vgic_its_restore_dte(struct vgic_its *its, u32 id,
238662306a36Sopenharmony_ci				void *ptr, void *opaque)
238762306a36Sopenharmony_ci{
238862306a36Sopenharmony_ci	struct its_device *dev;
238962306a36Sopenharmony_ci	u64 baser = its->baser_device_table;
239062306a36Sopenharmony_ci	gpa_t itt_addr;
239162306a36Sopenharmony_ci	u8 num_eventid_bits;
239262306a36Sopenharmony_ci	u64 entry = *(u64 *)ptr;
239362306a36Sopenharmony_ci	bool valid;
239462306a36Sopenharmony_ci	u32 offset;
239562306a36Sopenharmony_ci	int ret;
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	entry = le64_to_cpu(entry);
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
240062306a36Sopenharmony_ci	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
240162306a36Sopenharmony_ci	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
240262306a36Sopenharmony_ci			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	if (!valid)
240562306a36Sopenharmony_ci		return 1;
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	/* dte entry is valid */
240862306a36Sopenharmony_ci	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	if (!vgic_its_check_id(its, baser, id, NULL))
241162306a36Sopenharmony_ci		return -EINVAL;
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
241462306a36Sopenharmony_ci	if (IS_ERR(dev))
241562306a36Sopenharmony_ci		return PTR_ERR(dev);
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	ret = vgic_its_restore_itt(its, dev);
241862306a36Sopenharmony_ci	if (ret) {
241962306a36Sopenharmony_ci		vgic_its_free_device(its->dev->kvm, dev);
242062306a36Sopenharmony_ci		return ret;
242162306a36Sopenharmony_ci	}
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	return offset;
242462306a36Sopenharmony_ci}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_cistatic int vgic_its_device_cmp(void *priv, const struct list_head *a,
242762306a36Sopenharmony_ci			       const struct list_head *b)
242862306a36Sopenharmony_ci{
242962306a36Sopenharmony_ci	struct its_device *deva = container_of(a, struct its_device, dev_list);
243062306a36Sopenharmony_ci	struct its_device *devb = container_of(b, struct its_device, dev_list);
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	if (deva->device_id < devb->device_id)
243362306a36Sopenharmony_ci		return -1;
243462306a36Sopenharmony_ci	else
243562306a36Sopenharmony_ci		return 1;
243662306a36Sopenharmony_ci}
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci/**
243962306a36Sopenharmony_ci * vgic_its_save_device_tables - Save the device table and all ITT
244062306a36Sopenharmony_ci * into guest RAM
244162306a36Sopenharmony_ci *
244262306a36Sopenharmony_ci * L1/L2 handling is hidden by vgic_its_check_id() helper which directly
244362306a36Sopenharmony_ci * returns the GPA of the device entry
244462306a36Sopenharmony_ci */
244562306a36Sopenharmony_cistatic int vgic_its_save_device_tables(struct vgic_its *its)
244662306a36Sopenharmony_ci{
244762306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
244862306a36Sopenharmony_ci	u64 baser = its->baser_device_table;
244962306a36Sopenharmony_ci	struct its_device *dev;
245062306a36Sopenharmony_ci	int dte_esz = abi->dte_esz;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	if (!(baser & GITS_BASER_VALID))
245362306a36Sopenharmony_ci		return 0;
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	list_sort(NULL, &its->device_list, vgic_its_device_cmp);
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	list_for_each_entry(dev, &its->device_list, dev_list) {
245862306a36Sopenharmony_ci		int ret;
245962306a36Sopenharmony_ci		gpa_t eaddr;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci		if (!vgic_its_check_id(its, baser,
246262306a36Sopenharmony_ci				       dev->device_id, &eaddr))
246362306a36Sopenharmony_ci			return -EINVAL;
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci		ret = vgic_its_save_itt(its, dev);
246662306a36Sopenharmony_ci		if (ret)
246762306a36Sopenharmony_ci			return ret;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci		ret = vgic_its_save_dte(its, dev, eaddr, dte_esz);
247062306a36Sopenharmony_ci		if (ret)
247162306a36Sopenharmony_ci			return ret;
247262306a36Sopenharmony_ci	}
247362306a36Sopenharmony_ci	return 0;
247462306a36Sopenharmony_ci}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci/**
247762306a36Sopenharmony_ci * handle_l1_dte - callback used for L1 device table entries (2 stage case)
247862306a36Sopenharmony_ci *
247962306a36Sopenharmony_ci * @its: its handle
248062306a36Sopenharmony_ci * @id: index of the entry in the L1 table
248162306a36Sopenharmony_ci * @addr: kernel VA
248262306a36Sopenharmony_ci * @opaque: unused
248362306a36Sopenharmony_ci *
248462306a36Sopenharmony_ci * L1 table entries are scanned by steps of 1 entry
248562306a36Sopenharmony_ci * Return < 0 if error, 0 if last dte was found when scanning the L2
248662306a36Sopenharmony_ci * table, +1 otherwise (meaning next L1 entry must be scanned)
248762306a36Sopenharmony_ci */
248862306a36Sopenharmony_cistatic int handle_l1_dte(struct vgic_its *its, u32 id, void *addr,
248962306a36Sopenharmony_ci			 void *opaque)
249062306a36Sopenharmony_ci{
249162306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
249262306a36Sopenharmony_ci	int l2_start_id = id * (SZ_64K / abi->dte_esz);
249362306a36Sopenharmony_ci	u64 entry = *(u64 *)addr;
249462306a36Sopenharmony_ci	int dte_esz = abi->dte_esz;
249562306a36Sopenharmony_ci	gpa_t gpa;
249662306a36Sopenharmony_ci	int ret;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	entry = le64_to_cpu(entry);
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	if (!(entry & KVM_ITS_L1E_VALID_MASK))
250162306a36Sopenharmony_ci		return 1;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	gpa = entry & KVM_ITS_L1E_ADDR_MASK;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	ret = scan_its_table(its, gpa, SZ_64K, dte_esz,
250662306a36Sopenharmony_ci			     l2_start_id, vgic_its_restore_dte, NULL);
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	return ret;
250962306a36Sopenharmony_ci}
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci/**
251262306a36Sopenharmony_ci * vgic_its_restore_device_tables - Restore the device table and all ITT
251362306a36Sopenharmony_ci * from guest RAM to internal data structs
251462306a36Sopenharmony_ci */
251562306a36Sopenharmony_cistatic int vgic_its_restore_device_tables(struct vgic_its *its)
251662306a36Sopenharmony_ci{
251762306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
251862306a36Sopenharmony_ci	u64 baser = its->baser_device_table;
251962306a36Sopenharmony_ci	int l1_esz, ret;
252062306a36Sopenharmony_ci	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
252162306a36Sopenharmony_ci	gpa_t l1_gpa;
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	if (!(baser & GITS_BASER_VALID))
252462306a36Sopenharmony_ci		return 0;
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	l1_gpa = GITS_BASER_ADDR_48_to_52(baser);
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	if (baser & GITS_BASER_INDIRECT) {
252962306a36Sopenharmony_ci		l1_esz = GITS_LVL1_ENTRY_SIZE;
253062306a36Sopenharmony_ci		ret = scan_its_table(its, l1_gpa, l1_tbl_size, l1_esz, 0,
253162306a36Sopenharmony_ci				     handle_l1_dte, NULL);
253262306a36Sopenharmony_ci	} else {
253362306a36Sopenharmony_ci		l1_esz = abi->dte_esz;
253462306a36Sopenharmony_ci		ret = scan_its_table(its, l1_gpa, l1_tbl_size, l1_esz, 0,
253562306a36Sopenharmony_ci				     vgic_its_restore_dte, NULL);
253662306a36Sopenharmony_ci	}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	/* scan_its_table returns +1 if all entries are invalid */
253962306a36Sopenharmony_ci	if (ret > 0)
254062306a36Sopenharmony_ci		ret = 0;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	if (ret < 0)
254362306a36Sopenharmony_ci		vgic_its_free_device_list(its->dev->kvm, its);
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	return ret;
254662306a36Sopenharmony_ci}
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_cistatic int vgic_its_save_cte(struct vgic_its *its,
254962306a36Sopenharmony_ci			     struct its_collection *collection,
255062306a36Sopenharmony_ci			     gpa_t gpa, int esz)
255162306a36Sopenharmony_ci{
255262306a36Sopenharmony_ci	u64 val;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	val = (1ULL << KVM_ITS_CTE_VALID_SHIFT |
255562306a36Sopenharmony_ci	       ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
255662306a36Sopenharmony_ci	       collection->collection_id);
255762306a36Sopenharmony_ci	val = cpu_to_le64(val);
255862306a36Sopenharmony_ci	return vgic_write_guest_lock(its->dev->kvm, gpa, &val, esz);
255962306a36Sopenharmony_ci}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci/*
256262306a36Sopenharmony_ci * Restore a collection entry into the ITS collection table.
256362306a36Sopenharmony_ci * Return +1 on success, 0 if the entry was invalid (which should be
256462306a36Sopenharmony_ci * interpreted as end-of-table), and a negative error value for generic errors.
256562306a36Sopenharmony_ci */
256662306a36Sopenharmony_cistatic int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
256762306a36Sopenharmony_ci{
256862306a36Sopenharmony_ci	struct its_collection *collection;
256962306a36Sopenharmony_ci	struct kvm *kvm = its->dev->kvm;
257062306a36Sopenharmony_ci	u32 target_addr, coll_id;
257162306a36Sopenharmony_ci	u64 val;
257262306a36Sopenharmony_ci	int ret;
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci	BUG_ON(esz > sizeof(val));
257562306a36Sopenharmony_ci	ret = kvm_read_guest_lock(kvm, gpa, &val, esz);
257662306a36Sopenharmony_ci	if (ret)
257762306a36Sopenharmony_ci		return ret;
257862306a36Sopenharmony_ci	val = le64_to_cpu(val);
257962306a36Sopenharmony_ci	if (!(val & KVM_ITS_CTE_VALID_MASK))
258062306a36Sopenharmony_ci		return 0;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	target_addr = (u32)(val >> KVM_ITS_CTE_RDBASE_SHIFT);
258362306a36Sopenharmony_ci	coll_id = val & KVM_ITS_CTE_ICID_MASK;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	if (target_addr != COLLECTION_NOT_MAPPED &&
258662306a36Sopenharmony_ci	    target_addr >= atomic_read(&kvm->online_vcpus))
258762306a36Sopenharmony_ci		return -EINVAL;
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	collection = find_collection(its, coll_id);
259062306a36Sopenharmony_ci	if (collection)
259162306a36Sopenharmony_ci		return -EEXIST;
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	if (!vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL))
259462306a36Sopenharmony_ci		return -EINVAL;
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	ret = vgic_its_alloc_collection(its, &collection, coll_id);
259762306a36Sopenharmony_ci	if (ret)
259862306a36Sopenharmony_ci		return ret;
259962306a36Sopenharmony_ci	collection->target_addr = target_addr;
260062306a36Sopenharmony_ci	return 1;
260162306a36Sopenharmony_ci}
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci/**
260462306a36Sopenharmony_ci * vgic_its_save_collection_table - Save the collection table into
260562306a36Sopenharmony_ci * guest RAM
260662306a36Sopenharmony_ci */
260762306a36Sopenharmony_cistatic int vgic_its_save_collection_table(struct vgic_its *its)
260862306a36Sopenharmony_ci{
260962306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
261062306a36Sopenharmony_ci	u64 baser = its->baser_coll_table;
261162306a36Sopenharmony_ci	gpa_t gpa = GITS_BASER_ADDR_48_to_52(baser);
261262306a36Sopenharmony_ci	struct its_collection *collection;
261362306a36Sopenharmony_ci	u64 val;
261462306a36Sopenharmony_ci	size_t max_size, filled = 0;
261562306a36Sopenharmony_ci	int ret, cte_esz = abi->cte_esz;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	if (!(baser & GITS_BASER_VALID))
261862306a36Sopenharmony_ci		return 0;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci	list_for_each_entry(collection, &its->collection_list, coll_list) {
262362306a36Sopenharmony_ci		ret = vgic_its_save_cte(its, collection, gpa, cte_esz);
262462306a36Sopenharmony_ci		if (ret)
262562306a36Sopenharmony_ci			return ret;
262662306a36Sopenharmony_ci		gpa += cte_esz;
262762306a36Sopenharmony_ci		filled += cte_esz;
262862306a36Sopenharmony_ci	}
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	if (filled == max_size)
263162306a36Sopenharmony_ci		return 0;
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	/*
263462306a36Sopenharmony_ci	 * table is not fully filled, add a last dummy element
263562306a36Sopenharmony_ci	 * with valid bit unset
263662306a36Sopenharmony_ci	 */
263762306a36Sopenharmony_ci	val = 0;
263862306a36Sopenharmony_ci	BUG_ON(cte_esz > sizeof(val));
263962306a36Sopenharmony_ci	ret = vgic_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz);
264062306a36Sopenharmony_ci	return ret;
264162306a36Sopenharmony_ci}
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci/**
264462306a36Sopenharmony_ci * vgic_its_restore_collection_table - reads the collection table
264562306a36Sopenharmony_ci * in guest memory and restores the ITS internal state. Requires the
264662306a36Sopenharmony_ci * BASER registers to be restored before.
264762306a36Sopenharmony_ci */
264862306a36Sopenharmony_cistatic int vgic_its_restore_collection_table(struct vgic_its *its)
264962306a36Sopenharmony_ci{
265062306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
265162306a36Sopenharmony_ci	u64 baser = its->baser_coll_table;
265262306a36Sopenharmony_ci	int cte_esz = abi->cte_esz;
265362306a36Sopenharmony_ci	size_t max_size, read = 0;
265462306a36Sopenharmony_ci	gpa_t gpa;
265562306a36Sopenharmony_ci	int ret;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	if (!(baser & GITS_BASER_VALID))
265862306a36Sopenharmony_ci		return 0;
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	gpa = GITS_BASER_ADDR_48_to_52(baser);
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	while (read < max_size) {
266562306a36Sopenharmony_ci		ret = vgic_its_restore_cte(its, gpa, cte_esz);
266662306a36Sopenharmony_ci		if (ret <= 0)
266762306a36Sopenharmony_ci			break;
266862306a36Sopenharmony_ci		gpa += cte_esz;
266962306a36Sopenharmony_ci		read += cte_esz;
267062306a36Sopenharmony_ci	}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	if (ret > 0)
267362306a36Sopenharmony_ci		return 0;
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci	if (ret < 0)
267662306a36Sopenharmony_ci		vgic_its_free_collection_list(its->dev->kvm, its);
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci	return ret;
267962306a36Sopenharmony_ci}
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci/**
268262306a36Sopenharmony_ci * vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
268362306a36Sopenharmony_ci * according to v0 ABI
268462306a36Sopenharmony_ci */
268562306a36Sopenharmony_cistatic int vgic_its_save_tables_v0(struct vgic_its *its)
268662306a36Sopenharmony_ci{
268762306a36Sopenharmony_ci	int ret;
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	ret = vgic_its_save_device_tables(its);
269062306a36Sopenharmony_ci	if (ret)
269162306a36Sopenharmony_ci		return ret;
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	return vgic_its_save_collection_table(its);
269462306a36Sopenharmony_ci}
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ci/**
269762306a36Sopenharmony_ci * vgic_its_restore_tables_v0 - Restore the ITS tables from guest RAM
269862306a36Sopenharmony_ci * to internal data structs according to V0 ABI
269962306a36Sopenharmony_ci *
270062306a36Sopenharmony_ci */
270162306a36Sopenharmony_cistatic int vgic_its_restore_tables_v0(struct vgic_its *its)
270262306a36Sopenharmony_ci{
270362306a36Sopenharmony_ci	int ret;
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	ret = vgic_its_restore_collection_table(its);
270662306a36Sopenharmony_ci	if (ret)
270762306a36Sopenharmony_ci		return ret;
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci	ret = vgic_its_restore_device_tables(its);
271062306a36Sopenharmony_ci	if (ret)
271162306a36Sopenharmony_ci		vgic_its_free_collection_list(its->dev->kvm, its);
271262306a36Sopenharmony_ci	return ret;
271362306a36Sopenharmony_ci}
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_cistatic int vgic_its_commit_v0(struct vgic_its *its)
271662306a36Sopenharmony_ci{
271762306a36Sopenharmony_ci	const struct vgic_its_abi *abi;
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	abi = vgic_its_get_abi(its);
272062306a36Sopenharmony_ci	its->baser_coll_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
272162306a36Sopenharmony_ci	its->baser_device_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	its->baser_coll_table |= (GIC_ENCODE_SZ(abi->cte_esz, 5)
272462306a36Sopenharmony_ci					<< GITS_BASER_ENTRY_SIZE_SHIFT);
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	its->baser_device_table |= (GIC_ENCODE_SZ(abi->dte_esz, 5)
272762306a36Sopenharmony_ci					<< GITS_BASER_ENTRY_SIZE_SHIFT);
272862306a36Sopenharmony_ci	return 0;
272962306a36Sopenharmony_ci}
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_cistatic void vgic_its_reset(struct kvm *kvm, struct vgic_its *its)
273262306a36Sopenharmony_ci{
273362306a36Sopenharmony_ci	/* We need to keep the ABI specific field values */
273462306a36Sopenharmony_ci	its->baser_coll_table &= ~GITS_BASER_VALID;
273562306a36Sopenharmony_ci	its->baser_device_table &= ~GITS_BASER_VALID;
273662306a36Sopenharmony_ci	its->cbaser = 0;
273762306a36Sopenharmony_ci	its->creadr = 0;
273862306a36Sopenharmony_ci	its->cwriter = 0;
273962306a36Sopenharmony_ci	its->enabled = 0;
274062306a36Sopenharmony_ci	vgic_its_free_device_list(kvm, its);
274162306a36Sopenharmony_ci	vgic_its_free_collection_list(kvm, its);
274262306a36Sopenharmony_ci}
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_cistatic int vgic_its_has_attr(struct kvm_device *dev,
274562306a36Sopenharmony_ci			     struct kvm_device_attr *attr)
274662306a36Sopenharmony_ci{
274762306a36Sopenharmony_ci	switch (attr->group) {
274862306a36Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ADDR:
274962306a36Sopenharmony_ci		switch (attr->attr) {
275062306a36Sopenharmony_ci		case KVM_VGIC_ITS_ADDR_TYPE:
275162306a36Sopenharmony_ci			return 0;
275262306a36Sopenharmony_ci		}
275362306a36Sopenharmony_ci		break;
275462306a36Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_CTRL:
275562306a36Sopenharmony_ci		switch (attr->attr) {
275662306a36Sopenharmony_ci		case KVM_DEV_ARM_VGIC_CTRL_INIT:
275762306a36Sopenharmony_ci			return 0;
275862306a36Sopenharmony_ci		case KVM_DEV_ARM_ITS_CTRL_RESET:
275962306a36Sopenharmony_ci			return 0;
276062306a36Sopenharmony_ci		case KVM_DEV_ARM_ITS_SAVE_TABLES:
276162306a36Sopenharmony_ci			return 0;
276262306a36Sopenharmony_ci		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
276362306a36Sopenharmony_ci			return 0;
276462306a36Sopenharmony_ci		}
276562306a36Sopenharmony_ci		break;
276662306a36Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS:
276762306a36Sopenharmony_ci		return vgic_its_has_attr_regs(dev, attr);
276862306a36Sopenharmony_ci	}
276962306a36Sopenharmony_ci	return -ENXIO;
277062306a36Sopenharmony_ci}
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_cistatic int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
277362306a36Sopenharmony_ci{
277462306a36Sopenharmony_ci	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
277562306a36Sopenharmony_ci	int ret = 0;
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci	if (attr == KVM_DEV_ARM_VGIC_CTRL_INIT) /* Nothing to do */
277862306a36Sopenharmony_ci		return 0;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	mutex_lock(&kvm->lock);
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci	if (!lock_all_vcpus(kvm)) {
278362306a36Sopenharmony_ci		mutex_unlock(&kvm->lock);
278462306a36Sopenharmony_ci		return -EBUSY;
278562306a36Sopenharmony_ci	}
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	mutex_lock(&kvm->arch.config_lock);
278862306a36Sopenharmony_ci	mutex_lock(&its->its_lock);
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	switch (attr) {
279162306a36Sopenharmony_ci	case KVM_DEV_ARM_ITS_CTRL_RESET:
279262306a36Sopenharmony_ci		vgic_its_reset(kvm, its);
279362306a36Sopenharmony_ci		break;
279462306a36Sopenharmony_ci	case KVM_DEV_ARM_ITS_SAVE_TABLES:
279562306a36Sopenharmony_ci		ret = abi->save_tables(its);
279662306a36Sopenharmony_ci		break;
279762306a36Sopenharmony_ci	case KVM_DEV_ARM_ITS_RESTORE_TABLES:
279862306a36Sopenharmony_ci		ret = abi->restore_tables(its);
279962306a36Sopenharmony_ci		break;
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	mutex_unlock(&its->its_lock);
280362306a36Sopenharmony_ci	mutex_unlock(&kvm->arch.config_lock);
280462306a36Sopenharmony_ci	unlock_all_vcpus(kvm);
280562306a36Sopenharmony_ci	mutex_unlock(&kvm->lock);
280662306a36Sopenharmony_ci	return ret;
280762306a36Sopenharmony_ci}
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci/*
281062306a36Sopenharmony_ci * kvm_arch_allow_write_without_running_vcpu - allow writing guest memory
281162306a36Sopenharmony_ci * without the running VCPU when dirty ring is enabled.
281262306a36Sopenharmony_ci *
281362306a36Sopenharmony_ci * The running VCPU is required to track dirty guest pages when dirty ring
281462306a36Sopenharmony_ci * is enabled. Otherwise, the backup bitmap should be used to track the
281562306a36Sopenharmony_ci * dirty guest pages. When vgic/its tables are being saved, the backup
281662306a36Sopenharmony_ci * bitmap is used to track the dirty guest pages due to the missed running
281762306a36Sopenharmony_ci * VCPU in the period.
281862306a36Sopenharmony_ci */
281962306a36Sopenharmony_cibool kvm_arch_allow_write_without_running_vcpu(struct kvm *kvm)
282062306a36Sopenharmony_ci{
282162306a36Sopenharmony_ci	struct vgic_dist *dist = &kvm->arch.vgic;
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	return dist->table_write_in_progress;
282462306a36Sopenharmony_ci}
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_cistatic int vgic_its_set_attr(struct kvm_device *dev,
282762306a36Sopenharmony_ci			     struct kvm_device_attr *attr)
282862306a36Sopenharmony_ci{
282962306a36Sopenharmony_ci	struct vgic_its *its = dev->private;
283062306a36Sopenharmony_ci	int ret;
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	switch (attr->group) {
283362306a36Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
283462306a36Sopenharmony_ci		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
283562306a36Sopenharmony_ci		unsigned long type = (unsigned long)attr->attr;
283662306a36Sopenharmony_ci		u64 addr;
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci		if (type != KVM_VGIC_ITS_ADDR_TYPE)
283962306a36Sopenharmony_ci			return -ENODEV;
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci		if (copy_from_user(&addr, uaddr, sizeof(addr)))
284262306a36Sopenharmony_ci			return -EFAULT;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci		ret = vgic_check_iorange(dev->kvm, its->vgic_its_base,
284562306a36Sopenharmony_ci					 addr, SZ_64K, KVM_VGIC_V3_ITS_SIZE);
284662306a36Sopenharmony_ci		if (ret)
284762306a36Sopenharmony_ci			return ret;
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci		return vgic_register_its_iodev(dev->kvm, its, addr);
285062306a36Sopenharmony_ci	}
285162306a36Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_CTRL:
285262306a36Sopenharmony_ci		return vgic_its_ctrl(dev->kvm, its, attr->attr);
285362306a36Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
285462306a36Sopenharmony_ci		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
285562306a36Sopenharmony_ci		u64 reg;
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci		if (get_user(reg, uaddr))
285862306a36Sopenharmony_ci			return -EFAULT;
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci		return vgic_its_attr_regs_access(dev, attr, &reg, true);
286162306a36Sopenharmony_ci	}
286262306a36Sopenharmony_ci	}
286362306a36Sopenharmony_ci	return -ENXIO;
286462306a36Sopenharmony_ci}
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_cistatic int vgic_its_get_attr(struct kvm_device *dev,
286762306a36Sopenharmony_ci			     struct kvm_device_attr *attr)
286862306a36Sopenharmony_ci{
286962306a36Sopenharmony_ci	switch (attr->group) {
287062306a36Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
287162306a36Sopenharmony_ci		struct vgic_its *its = dev->private;
287262306a36Sopenharmony_ci		u64 addr = its->vgic_its_base;
287362306a36Sopenharmony_ci		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
287462306a36Sopenharmony_ci		unsigned long type = (unsigned long)attr->attr;
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci		if (type != KVM_VGIC_ITS_ADDR_TYPE)
287762306a36Sopenharmony_ci			return -ENODEV;
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci		if (copy_to_user(uaddr, &addr, sizeof(addr)))
288062306a36Sopenharmony_ci			return -EFAULT;
288162306a36Sopenharmony_ci		break;
288262306a36Sopenharmony_ci	}
288362306a36Sopenharmony_ci	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
288462306a36Sopenharmony_ci		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
288562306a36Sopenharmony_ci		u64 reg;
288662306a36Sopenharmony_ci		int ret;
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci		ret = vgic_its_attr_regs_access(dev, attr, &reg, false);
288962306a36Sopenharmony_ci		if (ret)
289062306a36Sopenharmony_ci			return ret;
289162306a36Sopenharmony_ci		return put_user(reg, uaddr);
289262306a36Sopenharmony_ci	}
289362306a36Sopenharmony_ci	default:
289462306a36Sopenharmony_ci		return -ENXIO;
289562306a36Sopenharmony_ci	}
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	return 0;
289862306a36Sopenharmony_ci}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_cistatic struct kvm_device_ops kvm_arm_vgic_its_ops = {
290162306a36Sopenharmony_ci	.name = "kvm-arm-vgic-its",
290262306a36Sopenharmony_ci	.create = vgic_its_create,
290362306a36Sopenharmony_ci	.destroy = vgic_its_destroy,
290462306a36Sopenharmony_ci	.set_attr = vgic_its_set_attr,
290562306a36Sopenharmony_ci	.get_attr = vgic_its_get_attr,
290662306a36Sopenharmony_ci	.has_attr = vgic_its_has_attr,
290762306a36Sopenharmony_ci};
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ciint kvm_vgic_register_its_device(void)
291062306a36Sopenharmony_ci{
291162306a36Sopenharmony_ci	return kvm_register_device_ops(&kvm_arm_vgic_its_ops,
291262306a36Sopenharmony_ci				       KVM_DEV_TYPE_ARM_VGIC_ITS);
291362306a36Sopenharmony_ci}
2914