gic.c (3302B)
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 17static const struct gic_common_ops *gic_common_ops; 18static struct spinlock gic_lock; 19 20static void gic_cpu_init(unsigned int cpu, void *redist_base) 21{ 22 gic_common_ops->gic_cpu_init(cpu, redist_base); 23} 24 25static void 26gic_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 52void 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 66void gic_irq_enable(unsigned int intid) 67{ 68 GUEST_ASSERT(gic_common_ops); 69 gic_common_ops->gic_irq_enable(intid); 70} 71 72void gic_irq_disable(unsigned int intid) 73{ 74 GUEST_ASSERT(gic_common_ops); 75 gic_common_ops->gic_irq_disable(intid); 76} 77 78unsigned 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 91void gic_set_eoi(unsigned int intid) 92{ 93 GUEST_ASSERT(gic_common_ops); 94 gic_common_ops->gic_write_eoir(intid); 95} 96 97void gic_set_dir(unsigned int intid) 98{ 99 GUEST_ASSERT(gic_common_ops); 100 gic_common_ops->gic_write_dir(intid); 101} 102 103void gic_set_eoi_split(bool split) 104{ 105 GUEST_ASSERT(gic_common_ops); 106 gic_common_ops->gic_set_eoi_split(split); 107} 108 109void gic_set_priority_mask(uint64_t pmr) 110{ 111 GUEST_ASSERT(gic_common_ops); 112 gic_common_ops->gic_set_priority_mask(pmr); 113} 114 115void gic_set_priority(unsigned int intid, unsigned int prio) 116{ 117 GUEST_ASSERT(gic_common_ops); 118 gic_common_ops->gic_set_priority(intid, prio); 119} 120 121void gic_irq_set_active(unsigned int intid) 122{ 123 GUEST_ASSERT(gic_common_ops); 124 gic_common_ops->gic_irq_set_active(intid); 125} 126 127void gic_irq_clear_active(unsigned int intid) 128{ 129 GUEST_ASSERT(gic_common_ops); 130 gic_common_ops->gic_irq_clear_active(intid); 131} 132 133bool gic_irq_get_active(unsigned int intid) 134{ 135 GUEST_ASSERT(gic_common_ops); 136 return gic_common_ops->gic_irq_get_active(intid); 137} 138 139void gic_irq_set_pending(unsigned int intid) 140{ 141 GUEST_ASSERT(gic_common_ops); 142 gic_common_ops->gic_irq_set_pending(intid); 143} 144 145void gic_irq_clear_pending(unsigned int intid) 146{ 147 GUEST_ASSERT(gic_common_ops); 148 gic_common_ops->gic_irq_clear_pending(intid); 149} 150 151bool gic_irq_get_pending(unsigned int intid) 152{ 153 GUEST_ASSERT(gic_common_ops); 154 return gic_common_ops->gic_irq_get_pending(intid); 155} 156 157void gic_irq_set_config(unsigned int intid, bool is_edge) 158{ 159 GUEST_ASSERT(gic_common_ops); 160 gic_common_ops->gic_irq_set_config(intid, is_edge); 161}