hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/irqchip/irq-gic-v4.c
....@@ -1,18 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2016,2017 ARM Limited, All Rights Reserved.
34 * Author: Marc Zyngier <marc.zyngier@arm.com>
4
- *
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License version 2 as
7
- * published by the Free Software Foundation.
8
- *
9
- * This program is distributed in the hope that it will be useful,
10
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- * GNU General Public License for more details.
13
- *
14
- * You should have received a copy of the GNU General Public License
15
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
165 */
176
187 #include <linux/interrupt.h>
....@@ -96,6 +85,53 @@
9685
9786 static struct irq_domain *gic_domain;
9887 static const struct irq_domain_ops *vpe_domain_ops;
88
+static const struct irq_domain_ops *sgi_domain_ops;
89
+
90
+static bool has_v4_1(void)
91
+{
92
+ return !!sgi_domain_ops;
93
+}
94
+
95
+static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
96
+{
97
+ char *name;
98
+ int sgi_base;
99
+
100
+ if (!has_v4_1())
101
+ return 0;
102
+
103
+ name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current));
104
+ if (!name)
105
+ goto err;
106
+
107
+ vpe->fwnode = irq_domain_alloc_named_id_fwnode(name, idx);
108
+ if (!vpe->fwnode)
109
+ goto err;
110
+
111
+ kfree(name);
112
+ name = NULL;
113
+
114
+ vpe->sgi_domain = irq_domain_create_linear(vpe->fwnode, 16,
115
+ sgi_domain_ops, vpe);
116
+ if (!vpe->sgi_domain)
117
+ goto err;
118
+
119
+ sgi_base = __irq_domain_alloc_irqs(vpe->sgi_domain, -1, 16,
120
+ NUMA_NO_NODE, vpe,
121
+ false, NULL);
122
+ if (sgi_base <= 0)
123
+ goto err;
124
+
125
+ return 0;
126
+
127
+err:
128
+ if (vpe->sgi_domain)
129
+ irq_domain_remove(vpe->sgi_domain);
130
+ if (vpe->fwnode)
131
+ irq_domain_free_fwnode(vpe->fwnode);
132
+ kfree(name);
133
+ return -ENOMEM;
134
+}
99135
100136 int its_alloc_vcpu_irqs(struct its_vm *vm)
101137 {
....@@ -123,8 +159,13 @@
123159 if (vpe_base_irq <= 0)
124160 goto err;
125161
126
- for (i = 0; i < vm->nr_vpes; i++)
162
+ for (i = 0; i < vm->nr_vpes; i++) {
163
+ int ret;
127164 vm->vpes[i]->irq = vpe_base_irq + i;
165
+ ret = its_alloc_vcpu_sgis(vm->vpes[i], i);
166
+ if (ret)
167
+ goto err;
168
+ }
128169
129170 return 0;
130171
....@@ -137,8 +178,28 @@
137178 return -ENOMEM;
138179 }
139180
181
+static void its_free_sgi_irqs(struct its_vm *vm)
182
+{
183
+ int i;
184
+
185
+ if (!has_v4_1())
186
+ return;
187
+
188
+ for (i = 0; i < vm->nr_vpes; i++) {
189
+ unsigned int irq = irq_find_mapping(vm->vpes[i]->sgi_domain, 0);
190
+
191
+ if (WARN_ON(!irq))
192
+ continue;
193
+
194
+ irq_domain_free_irqs(irq, 16);
195
+ irq_domain_remove(vm->vpes[i]->sgi_domain);
196
+ irq_domain_free_fwnode(vm->vpes[i]->fwnode);
197
+ }
198
+}
199
+
140200 void its_free_vcpu_irqs(struct its_vm *vm)
141201 {
202
+ its_free_sgi_irqs(vm);
142203 irq_domain_free_irqs(vm->vpes[0]->irq, vm->nr_vpes);
143204 irq_domain_remove(vm->domain);
144205 irq_domain_free_fwnode(vm->fwnode);
....@@ -149,16 +210,72 @@
149210 return irq_set_vcpu_affinity(vpe->irq, info);
150211 }
151212
152
-int its_schedule_vpe(struct its_vpe *vpe, bool on)
213
+int its_make_vpe_non_resident(struct its_vpe *vpe, bool db)
153214 {
154
- struct its_cmd_info info;
215
+ struct irq_desc *desc = irq_to_desc(vpe->irq);
216
+ struct its_cmd_info info = { };
217
+ int ret;
155218
156219 WARN_ON(preemptible());
157220
158
- info.cmd_type = on ? SCHEDULE_VPE : DESCHEDULE_VPE;
221
+ info.cmd_type = DESCHEDULE_VPE;
222
+ if (has_v4_1()) {
223
+ /* GICv4.1 can directly deal with doorbells */
224
+ info.req_db = db;
225
+ } else {
226
+ /* Undo the nested disable_irq() calls... */
227
+ while (db && irqd_irq_disabled(&desc->irq_data))
228
+ enable_irq(vpe->irq);
229
+ }
159230
160
- return its_send_vpe_cmd(vpe, &info);
231
+ ret = its_send_vpe_cmd(vpe, &info);
232
+ if (!ret)
233
+ vpe->resident = false;
234
+
235
+ vpe->ready = false;
236
+
237
+ return ret;
161238 }
239
+
240
+int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en)
241
+{
242
+ struct its_cmd_info info = { };
243
+ int ret;
244
+
245
+ WARN_ON(preemptible());
246
+
247
+ info.cmd_type = SCHEDULE_VPE;
248
+ if (has_v4_1()) {
249
+ info.g0en = g0en;
250
+ info.g1en = g1en;
251
+ } else {
252
+ /* Disabled the doorbell, as we're about to enter the guest */
253
+ disable_irq_nosync(vpe->irq);
254
+ }
255
+
256
+ ret = its_send_vpe_cmd(vpe, &info);
257
+ if (!ret)
258
+ vpe->resident = true;
259
+
260
+ return ret;
261
+}
262
+
263
+int its_commit_vpe(struct its_vpe *vpe)
264
+{
265
+ struct its_cmd_info info = {
266
+ .cmd_type = COMMIT_VPE,
267
+ };
268
+ int ret;
269
+
270
+ WARN_ON(preemptible());
271
+
272
+ ret = its_send_vpe_cmd(vpe, &info);
273
+ if (!ret)
274
+ vpe->ready = true;
275
+
276
+ return ret;
277
+}
278
+
162279
163280 int its_invall_vpe(struct its_vpe *vpe)
164281 {
....@@ -222,12 +339,28 @@
222339 return irq_set_vcpu_affinity(irq, &info);
223340 }
224341
225
-int its_init_v4(struct irq_domain *domain, const struct irq_domain_ops *ops)
342
+int its_prop_update_vsgi(int irq, u8 priority, bool group)
343
+{
344
+ struct its_cmd_info info = {
345
+ .cmd_type = PROP_UPDATE_VSGI,
346
+ {
347
+ .priority = priority,
348
+ .group = group,
349
+ },
350
+ };
351
+
352
+ return irq_set_vcpu_affinity(irq, &info);
353
+}
354
+
355
+int its_init_v4(struct irq_domain *domain,
356
+ const struct irq_domain_ops *vpe_ops,
357
+ const struct irq_domain_ops *sgi_ops)
226358 {
227359 if (domain) {
228360 pr_info("ITS: Enabling GICv4 support\n");
229361 gic_domain = domain;
230
- vpe_domain_ops = ops;
362
+ vpe_domain_ops = vpe_ops;
363
+ sgi_domain_ops = sgi_ops;
231364 return 0;
232365 }
233366