158 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * ARM Generic Interrupt Controller (GIC) support4 */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)21{22 gic_common_ops->gic_cpu_init(cpu);23}24 25static void gic_dist_init(enum gic_type type, unsigned int nr_cpus)26{27 const struct gic_common_ops *gic_ops = NULL;28 29 spin_lock(&gic_lock);30 31 /* Distributor initialization is needed only once per VM */32 if (gic_common_ops) {33 spin_unlock(&gic_lock);34 return;35 }36 37 if (type == GIC_V3)38 gic_ops = &gicv3_ops;39 40 GUEST_ASSERT(gic_ops);41 42 gic_ops->gic_init(nr_cpus);43 gic_common_ops = gic_ops;44 45 /* Make sure that the initialized data is visible to all the vCPUs */46 dsb(sy);47 48 spin_unlock(&gic_lock);49}50 51void gic_init(enum gic_type type, unsigned int nr_cpus)52{53 uint32_t cpu = guest_get_vcpuid();54 55 GUEST_ASSERT(type < GIC_TYPE_MAX);56 GUEST_ASSERT(nr_cpus);57 58 gic_dist_init(type, nr_cpus);59 gic_cpu_init(cpu);60}61 62void gic_irq_enable(unsigned int intid)63{64 GUEST_ASSERT(gic_common_ops);65 gic_common_ops->gic_irq_enable(intid);66}67 68void gic_irq_disable(unsigned int intid)69{70 GUEST_ASSERT(gic_common_ops);71 gic_common_ops->gic_irq_disable(intid);72}73 74unsigned int gic_get_and_ack_irq(void)75{76 uint64_t irqstat;77 unsigned int intid;78 79 GUEST_ASSERT(gic_common_ops);80 81 irqstat = gic_common_ops->gic_read_iar();82 intid = irqstat & GENMASK(23, 0);83 84 return intid;85}86 87void gic_set_eoi(unsigned int intid)88{89 GUEST_ASSERT(gic_common_ops);90 gic_common_ops->gic_write_eoir(intid);91}92 93void gic_set_dir(unsigned int intid)94{95 GUEST_ASSERT(gic_common_ops);96 gic_common_ops->gic_write_dir(intid);97}98 99void gic_set_eoi_split(bool split)100{101 GUEST_ASSERT(gic_common_ops);102 gic_common_ops->gic_set_eoi_split(split);103}104 105void gic_set_priority_mask(uint64_t pmr)106{107 GUEST_ASSERT(gic_common_ops);108 gic_common_ops->gic_set_priority_mask(pmr);109}110 111void gic_set_priority(unsigned int intid, unsigned int prio)112{113 GUEST_ASSERT(gic_common_ops);114 gic_common_ops->gic_set_priority(intid, prio);115}116 117void gic_irq_set_active(unsigned int intid)118{119 GUEST_ASSERT(gic_common_ops);120 gic_common_ops->gic_irq_set_active(intid);121}122 123void gic_irq_clear_active(unsigned int intid)124{125 GUEST_ASSERT(gic_common_ops);126 gic_common_ops->gic_irq_clear_active(intid);127}128 129bool gic_irq_get_active(unsigned int intid)130{131 GUEST_ASSERT(gic_common_ops);132 return gic_common_ops->gic_irq_get_active(intid);133}134 135void gic_irq_set_pending(unsigned int intid)136{137 GUEST_ASSERT(gic_common_ops);138 gic_common_ops->gic_irq_set_pending(intid);139}140 141void gic_irq_clear_pending(unsigned int intid)142{143 GUEST_ASSERT(gic_common_ops);144 gic_common_ops->gic_irq_clear_pending(intid);145}146 147bool gic_irq_get_pending(unsigned int intid)148{149 GUEST_ASSERT(gic_common_ops);150 return gic_common_ops->gic_irq_get_pending(intid);151}152 153void gic_irq_set_config(unsigned int intid, bool is_edge)154{155 GUEST_ASSERT(gic_common_ops);156 gic_common_ops->gic_irq_set_config(intid, is_edge);157}158