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,void * redist_base)2028281652SRaghavendra Rao Ananta static void gic_cpu_init(unsigned int cpu, void *redist_base)
2128281652SRaghavendra Rao Ananta {
2228281652SRaghavendra Rao Ananta 	gic_common_ops->gic_cpu_init(cpu, redist_base);
2328281652SRaghavendra Rao Ananta }
2428281652SRaghavendra Rao Ananta 
2528281652SRaghavendra Rao Ananta static void
gic_dist_init(enum gic_type type,unsigned int nr_cpus,void * dist_base)2628281652SRaghavendra Rao Ananta gic_dist_init(enum gic_type type, unsigned int nr_cpus, void *dist_base)
2728281652SRaghavendra Rao Ananta {
2828281652SRaghavendra Rao Ananta 	const struct gic_common_ops *gic_ops = NULL;
2928281652SRaghavendra Rao Ananta 
3028281652SRaghavendra Rao Ananta 	spin_lock(&gic_lock);
3128281652SRaghavendra Rao Ananta 
3228281652SRaghavendra Rao Ananta 	/* Distributor initialization is needed only once per VM */
3328281652SRaghavendra Rao Ananta 	if (gic_common_ops) {
3428281652SRaghavendra Rao Ananta 		spin_unlock(&gic_lock);
3528281652SRaghavendra Rao Ananta 		return;
3628281652SRaghavendra Rao Ananta 	}
3728281652SRaghavendra Rao Ananta 
3828281652SRaghavendra Rao Ananta 	if (type == GIC_V3)
3928281652SRaghavendra Rao Ananta 		gic_ops = &gicv3_ops;
4028281652SRaghavendra Rao Ananta 
4128281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_ops);
4228281652SRaghavendra Rao Ananta 
4328281652SRaghavendra Rao Ananta 	gic_ops->gic_init(nr_cpus, dist_base);
4428281652SRaghavendra Rao Ananta 	gic_common_ops = gic_ops;
4528281652SRaghavendra Rao Ananta 
4628281652SRaghavendra Rao Ananta 	/* Make sure that the initialized data is visible to all the vCPUs */
4728281652SRaghavendra Rao Ananta 	dsb(sy);
4828281652SRaghavendra Rao Ananta 
4928281652SRaghavendra Rao Ananta 	spin_unlock(&gic_lock);
5028281652SRaghavendra Rao Ananta }
5128281652SRaghavendra Rao Ananta 
gic_init(enum gic_type type,unsigned int nr_cpus,void * dist_base,void * redist_base)5228281652SRaghavendra Rao Ananta void gic_init(enum gic_type type, unsigned int nr_cpus,
5328281652SRaghavendra Rao Ananta 		void *dist_base, void *redist_base)
5428281652SRaghavendra Rao Ananta {
5528281652SRaghavendra Rao Ananta 	uint32_t cpu = guest_get_vcpuid();
5628281652SRaghavendra Rao Ananta 
5728281652SRaghavendra Rao Ananta 	GUEST_ASSERT(type < GIC_TYPE_MAX);
5828281652SRaghavendra Rao Ananta 	GUEST_ASSERT(dist_base);
5928281652SRaghavendra Rao Ananta 	GUEST_ASSERT(redist_base);
6028281652SRaghavendra Rao Ananta 	GUEST_ASSERT(nr_cpus);
6128281652SRaghavendra Rao Ananta 
6228281652SRaghavendra Rao Ananta 	gic_dist_init(type, nr_cpus, dist_base);
6328281652SRaghavendra Rao Ananta 	gic_cpu_init(cpu, redist_base);
6428281652SRaghavendra Rao Ananta }
6528281652SRaghavendra Rao Ananta 
gic_irq_enable(unsigned int intid)6628281652SRaghavendra Rao Ananta void gic_irq_enable(unsigned int intid)
6728281652SRaghavendra Rao Ananta {
6828281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_common_ops);
6928281652SRaghavendra Rao Ananta 	gic_common_ops->gic_irq_enable(intid);
7028281652SRaghavendra Rao Ananta }
7128281652SRaghavendra Rao Ananta 
gic_irq_disable(unsigned int intid)7228281652SRaghavendra Rao Ananta void gic_irq_disable(unsigned int intid)
7328281652SRaghavendra Rao Ananta {
7428281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_common_ops);
7528281652SRaghavendra Rao Ananta 	gic_common_ops->gic_irq_disable(intid);
7628281652SRaghavendra Rao Ananta }
7728281652SRaghavendra Rao Ananta 
gic_get_and_ack_irq(void)7828281652SRaghavendra Rao Ananta unsigned int gic_get_and_ack_irq(void)
7928281652SRaghavendra Rao Ananta {
8028281652SRaghavendra Rao Ananta 	uint64_t irqstat;
8128281652SRaghavendra Rao Ananta 	unsigned int intid;
8228281652SRaghavendra Rao Ananta 
8328281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_common_ops);
8428281652SRaghavendra Rao Ananta 
8528281652SRaghavendra Rao Ananta 	irqstat = gic_common_ops->gic_read_iar();
8628281652SRaghavendra Rao Ananta 	intid = irqstat & GENMASK(23, 0);
8728281652SRaghavendra Rao Ananta 
8828281652SRaghavendra Rao Ananta 	return intid;
8928281652SRaghavendra Rao Ananta }
9028281652SRaghavendra Rao Ananta 
gic_set_eoi(unsigned int intid)9128281652SRaghavendra Rao Ananta void gic_set_eoi(unsigned int intid)
9228281652SRaghavendra Rao Ananta {
9328281652SRaghavendra Rao Ananta 	GUEST_ASSERT(gic_common_ops);
9428281652SRaghavendra Rao Ananta 	gic_common_ops->gic_write_eoir(intid);
9528281652SRaghavendra Rao Ananta }
96*17ce617bSRicardo Koller 
gic_set_dir(unsigned int intid)97*17ce617bSRicardo Koller void gic_set_dir(unsigned int intid)
98*17ce617bSRicardo Koller {
99*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
100*17ce617bSRicardo Koller 	gic_common_ops->gic_write_dir(intid);
101*17ce617bSRicardo Koller }
102*17ce617bSRicardo Koller 
gic_set_eoi_split(bool split)103*17ce617bSRicardo Koller void gic_set_eoi_split(bool split)
104*17ce617bSRicardo Koller {
105*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
106*17ce617bSRicardo Koller 	gic_common_ops->gic_set_eoi_split(split);
107*17ce617bSRicardo Koller }
108*17ce617bSRicardo Koller 
gic_set_priority_mask(uint64_t pmr)109*17ce617bSRicardo Koller void gic_set_priority_mask(uint64_t pmr)
110*17ce617bSRicardo Koller {
111*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
112*17ce617bSRicardo Koller 	gic_common_ops->gic_set_priority_mask(pmr);
113*17ce617bSRicardo Koller }
114*17ce617bSRicardo Koller 
gic_set_priority(unsigned int intid,unsigned int prio)115*17ce617bSRicardo Koller void gic_set_priority(unsigned int intid, unsigned int prio)
116*17ce617bSRicardo Koller {
117*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
118*17ce617bSRicardo Koller 	gic_common_ops->gic_set_priority(intid, prio);
119*17ce617bSRicardo Koller }
120*17ce617bSRicardo Koller 
gic_irq_set_active(unsigned int intid)121*17ce617bSRicardo Koller void gic_irq_set_active(unsigned int intid)
122*17ce617bSRicardo Koller {
123*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
124*17ce617bSRicardo Koller 	gic_common_ops->gic_irq_set_active(intid);
125*17ce617bSRicardo Koller }
126*17ce617bSRicardo Koller 
gic_irq_clear_active(unsigned int intid)127*17ce617bSRicardo Koller void gic_irq_clear_active(unsigned int intid)
128*17ce617bSRicardo Koller {
129*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
130*17ce617bSRicardo Koller 	gic_common_ops->gic_irq_clear_active(intid);
131*17ce617bSRicardo Koller }
132*17ce617bSRicardo Koller 
gic_irq_get_active(unsigned int intid)133*17ce617bSRicardo Koller bool gic_irq_get_active(unsigned int intid)
134*17ce617bSRicardo Koller {
135*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
136*17ce617bSRicardo Koller 	return gic_common_ops->gic_irq_get_active(intid);
137*17ce617bSRicardo Koller }
138*17ce617bSRicardo Koller 
gic_irq_set_pending(unsigned int intid)139*17ce617bSRicardo Koller void gic_irq_set_pending(unsigned int intid)
140*17ce617bSRicardo Koller {
141*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
142*17ce617bSRicardo Koller 	gic_common_ops->gic_irq_set_pending(intid);
143*17ce617bSRicardo Koller }
144*17ce617bSRicardo Koller 
gic_irq_clear_pending(unsigned int intid)145*17ce617bSRicardo Koller void gic_irq_clear_pending(unsigned int intid)
146*17ce617bSRicardo Koller {
147*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
148*17ce617bSRicardo Koller 	gic_common_ops->gic_irq_clear_pending(intid);
149*17ce617bSRicardo Koller }
150*17ce617bSRicardo Koller 
gic_irq_get_pending(unsigned int intid)151*17ce617bSRicardo Koller bool gic_irq_get_pending(unsigned int intid)
152*17ce617bSRicardo Koller {
153*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
154*17ce617bSRicardo Koller 	return gic_common_ops->gic_irq_get_pending(intid);
155*17ce617bSRicardo Koller }
156*17ce617bSRicardo Koller 
gic_irq_set_config(unsigned int intid,bool is_edge)157*17ce617bSRicardo Koller void gic_irq_set_config(unsigned int intid, bool is_edge)
158*17ce617bSRicardo Koller {
159*17ce617bSRicardo Koller 	GUEST_ASSERT(gic_common_ops);
160*17ce617bSRicardo Koller 	gic_common_ops->gic_irq_set_config(intid, is_edge);
161*17ce617bSRicardo Koller }
162