1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ARM Generic Interrupt Controller (GIC) support 4 */ 5 6 #include <errno.h> 7 #include <linux/bits.h> 8 #include <linux/sizes.h> 9 10 #include "kvm_util.h" 11 12 #include <gic.h> 13 #include "gic_private.h" 14 #include "processor.h" 15 #include "spinlock.h" 16 17 static const struct gic_common_ops *gic_common_ops; 18 static struct spinlock gic_lock; 19 20 static void gic_cpu_init(unsigned int cpu, void *redist_base) 21 { 22 gic_common_ops->gic_cpu_init(cpu, redist_base); 23 } 24 25 static void 26 gic_dist_init(enum gic_type type, unsigned int nr_cpus, void *dist_base) 27 { 28 const struct gic_common_ops *gic_ops = NULL; 29 30 spin_lock(&gic_lock); 31 32 /* Distributor initialization is needed only once per VM */ 33 if (gic_common_ops) { 34 spin_unlock(&gic_lock); 35 return; 36 } 37 38 if (type == GIC_V3) 39 gic_ops = &gicv3_ops; 40 41 GUEST_ASSERT(gic_ops); 42 43 gic_ops->gic_init(nr_cpus, dist_base); 44 gic_common_ops = gic_ops; 45 46 /* Make sure that the initialized data is visible to all the vCPUs */ 47 dsb(sy); 48 49 spin_unlock(&gic_lock); 50 } 51 52 void gic_init(enum gic_type type, unsigned int nr_cpus, 53 void *dist_base, void *redist_base) 54 { 55 uint32_t cpu = guest_get_vcpuid(); 56 57 GUEST_ASSERT(type < GIC_TYPE_MAX); 58 GUEST_ASSERT(dist_base); 59 GUEST_ASSERT(redist_base); 60 GUEST_ASSERT(nr_cpus); 61 62 gic_dist_init(type, nr_cpus, dist_base); 63 gic_cpu_init(cpu, redist_base); 64 } 65 66 void gic_irq_enable(unsigned int intid) 67 { 68 GUEST_ASSERT(gic_common_ops); 69 gic_common_ops->gic_irq_enable(intid); 70 } 71 72 void gic_irq_disable(unsigned int intid) 73 { 74 GUEST_ASSERT(gic_common_ops); 75 gic_common_ops->gic_irq_disable(intid); 76 } 77 78 unsigned int gic_get_and_ack_irq(void) 79 { 80 uint64_t irqstat; 81 unsigned int intid; 82 83 GUEST_ASSERT(gic_common_ops); 84 85 irqstat = gic_common_ops->gic_read_iar(); 86 intid = irqstat & GENMASK(23, 0); 87 88 return intid; 89 } 90 91 void gic_set_eoi(unsigned int intid) 92 { 93 GUEST_ASSERT(gic_common_ops); 94 gic_common_ops->gic_write_eoir(intid); 95 } 96