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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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