Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/kvm/lib/arm64/gic.c
49679 views
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)
21
{
22
gic_common_ops->gic_cpu_init(cpu);
23
}
24
25
static 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
51
void 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
62
void gic_irq_enable(unsigned int intid)
63
{
64
GUEST_ASSERT(gic_common_ops);
65
gic_common_ops->gic_irq_enable(intid);
66
}
67
68
void gic_irq_disable(unsigned int intid)
69
{
70
GUEST_ASSERT(gic_common_ops);
71
gic_common_ops->gic_irq_disable(intid);
72
}
73
74
unsigned 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
87
void gic_set_eoi(unsigned int intid)
88
{
89
GUEST_ASSERT(gic_common_ops);
90
gic_common_ops->gic_write_eoir(intid);
91
}
92
93
void gic_set_dir(unsigned int intid)
94
{
95
GUEST_ASSERT(gic_common_ops);
96
gic_common_ops->gic_write_dir(intid);
97
}
98
99
void gic_set_eoi_split(bool split)
100
{
101
GUEST_ASSERT(gic_common_ops);
102
gic_common_ops->gic_set_eoi_split(split);
103
}
104
105
void 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
111
void 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
117
void 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
123
void 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
129
bool 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
135
void 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
141
void 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
147
bool 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
153
void 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
159
void gic_irq_set_group(unsigned int intid, bool group)
160
{
161
GUEST_ASSERT(gic_common_ops);
162
gic_common_ops->gic_irq_set_group(intid, group);
163
}
164
165