Linux Audio

Check our new training course

Loading...
  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}