Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ARM Generic Interrupt Controller (GIC) support
0004  */
0005 
0006 #include <errno.h>
0007 #include <linux/bits.h>
0008 #include <linux/sizes.h>
0009 
0010 #include "kvm_util.h"
0011 
0012 #include <gic.h>
0013 #include "gic_private.h"
0014 #include "processor.h"
0015 #include "spinlock.h"
0016 
0017 static const struct gic_common_ops *gic_common_ops;
0018 static struct spinlock gic_lock;
0019 
0020 static void gic_cpu_init(unsigned int cpu, void *redist_base)
0021 {
0022     gic_common_ops->gic_cpu_init(cpu, redist_base);
0023 }
0024 
0025 static void
0026 gic_dist_init(enum gic_type type, unsigned int nr_cpus, void *dist_base)
0027 {
0028     const struct gic_common_ops *gic_ops = NULL;
0029 
0030     spin_lock(&gic_lock);
0031 
0032     /* Distributor initialization is needed only once per VM */
0033     if (gic_common_ops) {
0034         spin_unlock(&gic_lock);
0035         return;
0036     }
0037 
0038     if (type == GIC_V3)
0039         gic_ops = &gicv3_ops;
0040 
0041     GUEST_ASSERT(gic_ops);
0042 
0043     gic_ops->gic_init(nr_cpus, dist_base);
0044     gic_common_ops = gic_ops;
0045 
0046     /* Make sure that the initialized data is visible to all the vCPUs */
0047     dsb(sy);
0048 
0049     spin_unlock(&gic_lock);
0050 }
0051 
0052 void gic_init(enum gic_type type, unsigned int nr_cpus,
0053         void *dist_base, void *redist_base)
0054 {
0055     uint32_t cpu = guest_get_vcpuid();
0056 
0057     GUEST_ASSERT(type < GIC_TYPE_MAX);
0058     GUEST_ASSERT(dist_base);
0059     GUEST_ASSERT(redist_base);
0060     GUEST_ASSERT(nr_cpus);
0061 
0062     gic_dist_init(type, nr_cpus, dist_base);
0063     gic_cpu_init(cpu, redist_base);
0064 }
0065 
0066 void gic_irq_enable(unsigned int intid)
0067 {
0068     GUEST_ASSERT(gic_common_ops);
0069     gic_common_ops->gic_irq_enable(intid);
0070 }
0071 
0072 void gic_irq_disable(unsigned int intid)
0073 {
0074     GUEST_ASSERT(gic_common_ops);
0075     gic_common_ops->gic_irq_disable(intid);
0076 }
0077 
0078 unsigned int gic_get_and_ack_irq(void)
0079 {
0080     uint64_t irqstat;
0081     unsigned int intid;
0082 
0083     GUEST_ASSERT(gic_common_ops);
0084 
0085     irqstat = gic_common_ops->gic_read_iar();
0086     intid = irqstat & GENMASK(23, 0);
0087 
0088     return intid;
0089 }
0090 
0091 void gic_set_eoi(unsigned int intid)
0092 {
0093     GUEST_ASSERT(gic_common_ops);
0094     gic_common_ops->gic_write_eoir(intid);
0095 }
0096 
0097 void gic_set_dir(unsigned int intid)
0098 {
0099     GUEST_ASSERT(gic_common_ops);
0100     gic_common_ops->gic_write_dir(intid);
0101 }
0102 
0103 void gic_set_eoi_split(bool split)
0104 {
0105     GUEST_ASSERT(gic_common_ops);
0106     gic_common_ops->gic_set_eoi_split(split);
0107 }
0108 
0109 void gic_set_priority_mask(uint64_t pmr)
0110 {
0111     GUEST_ASSERT(gic_common_ops);
0112     gic_common_ops->gic_set_priority_mask(pmr);
0113 }
0114 
0115 void gic_set_priority(unsigned int intid, unsigned int prio)
0116 {
0117     GUEST_ASSERT(gic_common_ops);
0118     gic_common_ops->gic_set_priority(intid, prio);
0119 }
0120 
0121 void gic_irq_set_active(unsigned int intid)
0122 {
0123     GUEST_ASSERT(gic_common_ops);
0124     gic_common_ops->gic_irq_set_active(intid);
0125 }
0126 
0127 void gic_irq_clear_active(unsigned int intid)
0128 {
0129     GUEST_ASSERT(gic_common_ops);
0130     gic_common_ops->gic_irq_clear_active(intid);
0131 }
0132 
0133 bool gic_irq_get_active(unsigned int intid)
0134 {
0135     GUEST_ASSERT(gic_common_ops);
0136     return gic_common_ops->gic_irq_get_active(intid);
0137 }
0138 
0139 void gic_irq_set_pending(unsigned int intid)
0140 {
0141     GUEST_ASSERT(gic_common_ops);
0142     gic_common_ops->gic_irq_set_pending(intid);
0143 }
0144 
0145 void gic_irq_clear_pending(unsigned int intid)
0146 {
0147     GUEST_ASSERT(gic_common_ops);
0148     gic_common_ops->gic_irq_clear_pending(intid);
0149 }
0150 
0151 bool gic_irq_get_pending(unsigned int intid)
0152 {
0153     GUEST_ASSERT(gic_common_ops);
0154     return gic_common_ops->gic_irq_get_pending(intid);
0155 }
0156 
0157 void gic_irq_set_config(unsigned int intid, bool is_edge)
0158 {
0159     GUEST_ASSERT(gic_common_ops);
0160     gic_common_ops->gic_irq_set_config(intid, is_edge);
0161 }