xref: /linux/tools/testing/selftests/kvm/lib/aarch64/gic.c (revision f4b0c4b508364fde023e4f7b9f23f7e38c663dfe)
128281652SRaghavendra Rao Ananta // SPDX-License-Identifier: GPL-2.0
228281652SRaghavendra Rao Ananta /*
328281652SRaghavendra Rao Ananta  * ARM Generic Interrupt Controller (GIC) support
428281652SRaghavendra Rao Ananta  */
528281652SRaghavendra Rao Ananta 
628281652SRaghavendra Rao Ananta #include <errno.h>
728281652SRaghavendra Rao Ananta #include <linux/bits.h>
828281652SRaghavendra Rao Ananta #include <linux/sizes.h>
928281652SRaghavendra Rao Ananta 
1028281652SRaghavendra Rao Ananta #include "kvm_util.h"
1128281652SRaghavendra Rao Ananta 
1228281652SRaghavendra Rao Ananta #include <gic.h>
1328281652SRaghavendra Rao Ananta #include "gic_private.h"
1428281652SRaghavendra Rao Ananta #include "processor.h"
1528281652SRaghavendra Rao Ananta #include "spinlock.h"
1628281652SRaghavendra Rao Ananta 
1728281652SRaghavendra Rao Ananta static const struct gic_common_ops *gic_common_ops;
1828281652SRaghavendra Rao Ananta static struct spinlock gic_lock;
1928281652SRaghavendra Rao Ananta 
gic_cpu_init(unsigned int cpu)20*1505bc70SOliver Upton static void gic_cpu_init(unsigned int cpu)
2128281652SRaghavendra Rao Ananta {
22*1505bc70SOliver Upton 	gic_common_ops->gic_cpu_init(cpu);
2328281652SRaghavendra Rao Ananta }
2428281652SRaghavendra Rao Ananta 
gic_dist_init(enum gic_type type,unsigned int nr_cpus)25*1505bc70SOliver Upton static void gic_dist_init(enum gic_type type, unsigned int nr_cpus)
2628281652SRaghavendra Rao Ananta {
2728281652SRaghavendra Rao Ananta 	const struct gic_common_ops *gic_ops = NULL;
2828281652SRaghavendra Rao Ananta 
2928281652SRaghavendra Rao Ananta 	spin_lock(&gic_lock);
3028281652SRaghavendra Rao Ananta 
3128281652SRaghavendra Rao Ananta 	/* Distributor initialization is needed only once per VM */
3228281652SRaghavendra Rao Ananta 	if (gic_common_ops) {
3328281652SRaghavendra Rao Ananta 		spin_unlock(&gic_lock);
3428281652SRaghavendra Rao Ananta 		return;
3528281652SRaghavendra Rao Ananta 	}
3628281652SRaghavendra Rao Ananta 
3728281652SRaghavendra Rao Ananta 	if (type == GIC_V3)
3828281652SRaghavendra Rao Ananta 		gic_ops = &gicv3_ops;
3928281652SRaghavendra Rao Ananta 
4028281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_ops);
4128281652SRaghavendra Rao Ananta 
42*1505bc70SOliver Upton 	gic_ops->gic_init(nr_cpus);
4328281652SRaghavendra Rao Ananta 	gic_common_ops = gic_ops;
4428281652SRaghavendra Rao Ananta 
4528281652SRaghavendra Rao Ananta 	/* Make sure that the initialized data is visible to all the vCPUs */
4628281652SRaghavendra Rao Ananta 	dsb(sy);
4728281652SRaghavendra Rao Ananta 
4828281652SRaghavendra Rao Ananta 	spin_unlock(&gic_lock);
4928281652SRaghavendra Rao Ananta }
5028281652SRaghavendra Rao Ananta 
gic_init(enum gic_type type,unsigned int nr_cpus)51*1505bc70SOliver Upton void gic_init(enum gic_type type, unsigned int nr_cpus)
5228281652SRaghavendra Rao Ananta {
5328281652SRaghavendra Rao Ananta 	uint32_t cpu = guest_get_vcpuid();
5428281652SRaghavendra Rao Ananta 
5528281652SRaghavendra Rao Ananta 	GUEST_ASSERT(type < GIC_TYPE_MAX);
5628281652SRaghavendra Rao Ananta 	GUEST_ASSERT(nr_cpus);
5728281652SRaghavendra Rao Ananta 
58*1505bc70SOliver Upton 	gic_dist_init(type, nr_cpus);
59*1505bc70SOliver Upton 	gic_cpu_init(cpu);
6028281652SRaghavendra Rao Ananta }
6128281652SRaghavendra Rao Ananta 
gic_irq_enable(unsigned int intid)6228281652SRaghavendra Rao Ananta void gic_irq_enable(unsigned int intid)
6328281652SRaghavendra Rao Ananta {
6428281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_common_ops);
6528281652SRaghavendra Rao Ananta 	gic_common_ops->gic_irq_enable(intid);
6628281652SRaghavendra Rao Ananta }
6728281652SRaghavendra Rao Ananta 
gic_irq_disable(unsigned int intid)6828281652SRaghavendra Rao Ananta void gic_irq_disable(unsigned int intid)
6928281652SRaghavendra Rao Ananta {
7028281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_common_ops);
7128281652SRaghavendra Rao Ananta 	gic_common_ops->gic_irq_disable(intid);
7228281652SRaghavendra Rao Ananta }
7328281652SRaghavendra Rao Ananta 
gic_get_and_ack_irq(void)7428281652SRaghavendra Rao Ananta unsigned int gic_get_and_ack_irq(void)
7528281652SRaghavendra Rao Ananta {
7628281652SRaghavendra Rao Ananta 	uint64_t irqstat;
7728281652SRaghavendra Rao Ananta 	unsigned int intid;
7828281652SRaghavendra Rao Ananta 
7928281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_common_ops);
8028281652SRaghavendra Rao Ananta 
8128281652SRaghavendra Rao Ananta 	irqstat = gic_common_ops->gic_read_iar();
8228281652SRaghavendra Rao Ananta 	intid = irqstat & GENMASK(23, 0);
8328281652SRaghavendra Rao Ananta 
8428281652SRaghavendra Rao Ananta 	return intid;
8528281652SRaghavendra Rao Ananta }
8628281652SRaghavendra Rao Ananta 
gic_set_eoi(unsigned int intid)8728281652SRaghavendra Rao Ananta void gic_set_eoi(unsigned int intid)
8828281652SRaghavendra Rao Ananta {
8928281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_common_ops);
9028281652SRaghavendra Rao Ananta 	gic_common_ops->gic_write_eoir(intid);
9128281652SRaghavendra Rao Ananta }
9217ce617bSRicardo Koller 
gic_set_dir(unsigned int intid)9317ce617bSRicardo Koller void gic_set_dir(unsigned int intid)
9417ce617bSRicardo Koller {
9517ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
9617ce617bSRicardo Koller 	gic_common_ops->gic_write_dir(intid);
9717ce617bSRicardo Koller }
9817ce617bSRicardo Koller 
gic_set_eoi_split(bool split)9917ce617bSRicardo Koller void gic_set_eoi_split(bool split)
10017ce617bSRicardo Koller {
10117ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
10217ce617bSRicardo Koller 	gic_common_ops->gic_set_eoi_split(split);
10317ce617bSRicardo Koller }
10417ce617bSRicardo Koller 
gic_set_priority_mask(uint64_t pmr)10517ce617bSRicardo Koller void gic_set_priority_mask(uint64_t pmr)
10617ce617bSRicardo Koller {
10717ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
10817ce617bSRicardo Koller 	gic_common_ops->gic_set_priority_mask(pmr);
10917ce617bSRicardo Koller }
11017ce617bSRicardo Koller 
gic_set_priority(unsigned int intid,unsigned int prio)11117ce617bSRicardo Koller void gic_set_priority(unsigned int intid, unsigned int prio)
11217ce617bSRicardo Koller {
11317ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
11417ce617bSRicardo Koller 	gic_common_ops->gic_set_priority(intid, prio);
11517ce617bSRicardo Koller }
11617ce617bSRicardo Koller 
gic_irq_set_active(unsigned int intid)11717ce617bSRicardo Koller void gic_irq_set_active(unsigned int intid)
11817ce617bSRicardo Koller {
11917ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
12017ce617bSRicardo Koller 	gic_common_ops->gic_irq_set_active(intid);
12117ce617bSRicardo Koller }
12217ce617bSRicardo Koller 
gic_irq_clear_active(unsigned int intid)12317ce617bSRicardo Koller void gic_irq_clear_active(unsigned int intid)
12417ce617bSRicardo Koller {
12517ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
12617ce617bSRicardo Koller 	gic_common_ops->gic_irq_clear_active(intid);
12717ce617bSRicardo Koller }
12817ce617bSRicardo Koller 
gic_irq_get_active(unsigned int intid)12917ce617bSRicardo Koller bool gic_irq_get_active(unsigned int intid)
13017ce617bSRicardo Koller {
13117ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
13217ce617bSRicardo Koller 	return gic_common_ops->gic_irq_get_active(intid);
13317ce617bSRicardo Koller }
13417ce617bSRicardo Koller 
gic_irq_set_pending(unsigned int intid)13517ce617bSRicardo Koller void gic_irq_set_pending(unsigned int intid)
13617ce617bSRicardo Koller {
13717ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
13817ce617bSRicardo Koller 	gic_common_ops->gic_irq_set_pending(intid);
13917ce617bSRicardo Koller }
14017ce617bSRicardo Koller 
gic_irq_clear_pending(unsigned int intid)14117ce617bSRicardo Koller void gic_irq_clear_pending(unsigned int intid)
14217ce617bSRicardo Koller {
14317ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
14417ce617bSRicardo Koller 	gic_common_ops->gic_irq_clear_pending(intid);
14517ce617bSRicardo Koller }
14617ce617bSRicardo Koller 
gic_irq_get_pending(unsigned int intid)14717ce617bSRicardo Koller bool gic_irq_get_pending(unsigned int intid)
14817ce617bSRicardo Koller {
14917ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
15017ce617bSRicardo Koller 	return gic_common_ops->gic_irq_get_pending(intid);
15117ce617bSRicardo Koller }
15217ce617bSRicardo Koller 
gic_irq_set_config(unsigned int intid,bool is_edge)15317ce617bSRicardo Koller void gic_irq_set_config(unsigned int intid, bool is_edge)
15417ce617bSRicardo Koller {
15517ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
15617ce617bSRicardo Koller 	gic_common_ops->gic_irq_set_config(intid, is_edge);
15717ce617bSRicardo Koller }
158