Skip to content

Commit 771df8c

Browse files
author
Marc Zyngier
committed
Merge branch 'irq/gic-v4.1' into irq/irqchip-next
Signed-off-by: Marc Zyngier <[email protected]>
2 parents 00760d3 + 009384b commit 771df8c

File tree

9 files changed

+600
-55
lines changed

9 files changed

+600
-55
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 400 additions & 22 deletions
Large diffs are not rendered by default.

drivers/irqchip/irq-gic-v3.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,7 @@ static void __init gic_dist_init(void)
723723
unsigned int i;
724724
u64 affinity;
725725
void __iomem *base = gic_data.dist_base;
726+
u32 val;
726727

727728
/* Disable the distributor */
728729
writel_relaxed(0, base + GICD_CTLR);
@@ -755,9 +756,14 @@ static void __init gic_dist_init(void)
755756
/* Now do the common stuff, and wait for the distributor to drain */
756757
gic_dist_config(base, GIC_LINE_NR, gic_dist_wait_for_rwp);
757758

759+
val = GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1;
760+
if (gic_data.rdists.gicd_typer2 & GICD_TYPER2_nASSGIcap) {
761+
pr_info("Enabling SGIs without active state\n");
762+
val |= GICD_CTLR_nASSGIreq;
763+
}
764+
758765
/* Enable distributor with ARE, Group1 */
759-
writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
760-
base + GICD_CTLR);
766+
writel_relaxed(val, base + GICD_CTLR);
761767

762768
/*
763769
* Set all global interrupts to the boot CPU only. ARE must be
@@ -828,6 +834,7 @@ static int __gic_populate_rdist(struct redist_region *region, void __iomem *ptr)
828834
typer = gic_read_typer(ptr + GICR_TYPER);
829835
if ((typer >> 32) == aff) {
830836
u64 offset = ptr - region->redist_base;
837+
raw_spin_lock_init(&gic_data_rdist()->rd_lock);
831838
gic_data_rdist_rd_base() = ptr;
832839
gic_data_rdist()->phys_base = region->phys_base + offset;
833840

@@ -1758,6 +1765,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
17581765
gic_v3_kvm_info.vcpu = r;
17591766

17601767
gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
1768+
gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
17611769
gic_set_kvm_info(&gic_v3_kvm_info);
17621770
}
17631771

@@ -2073,6 +2081,7 @@ static void __init gic_acpi_setup_kvm_info(void)
20732081
}
20742082

20752083
gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
2084+
gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
20762085
gic_set_kvm_info(&gic_v3_kvm_info);
20772086
}
20782087

drivers/irqchip/irq-gic-v4.c

Lines changed: 127 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,53 @@
8585

8686
static struct irq_domain *gic_domain;
8787
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+
}
88135

89136
int its_alloc_vcpu_irqs(struct its_vm *vm)
90137
{
@@ -112,8 +159,13 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
112159
if (vpe_base_irq <= 0)
113160
goto err;
114161

115-
for (i = 0; i < vm->nr_vpes; i++)
162+
for (i = 0; i < vm->nr_vpes; i++) {
163+
int ret;
116164
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+
}
117169

118170
return 0;
119171

@@ -126,8 +178,28 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
126178
return -ENOMEM;
127179
}
128180

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+
129200
void its_free_vcpu_irqs(struct its_vm *vm)
130201
{
202+
its_free_sgi_irqs(vm);
131203
irq_domain_free_irqs(vm->vpes[0]->irq, vm->nr_vpes);
132204
irq_domain_remove(vm->domain);
133205
irq_domain_free_fwnode(vm->fwnode);
@@ -138,18 +210,50 @@ static int its_send_vpe_cmd(struct its_vpe *vpe, struct its_cmd_info *info)
138210
return irq_set_vcpu_affinity(vpe->irq, info);
139211
}
140212

141-
int its_schedule_vpe(struct its_vpe *vpe, bool on)
213+
int its_make_vpe_non_resident(struct its_vpe *vpe, bool db)
214+
{
215+
struct irq_desc *desc = irq_to_desc(vpe->irq);
216+
struct its_cmd_info info = { };
217+
int ret;
218+
219+
WARN_ON(preemptible());
220+
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+
}
230+
231+
ret = its_send_vpe_cmd(vpe, &info);
232+
if (!ret)
233+
vpe->resident = false;
234+
235+
return ret;
236+
}
237+
238+
int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en)
142239
{
143-
struct its_cmd_info info;
240+
struct its_cmd_info info = { };
144241
int ret;
145242

146243
WARN_ON(preemptible());
147244

148-
info.cmd_type = on ? SCHEDULE_VPE : DESCHEDULE_VPE;
245+
info.cmd_type = SCHEDULE_VPE;
246+
if (has_v4_1()) {
247+
info.g0en = g0en;
248+
info.g1en = g1en;
249+
} else {
250+
/* Disabled the doorbell, as we're about to enter the guest */
251+
disable_irq_nosync(vpe->irq);
252+
}
149253

150254
ret = its_send_vpe_cmd(vpe, &info);
151255
if (!ret)
152-
vpe->resident = on;
256+
vpe->resident = true;
153257

154258
return ret;
155259
}
@@ -216,12 +320,28 @@ int its_prop_update_vlpi(int irq, u8 config, bool inv)
216320
return irq_set_vcpu_affinity(irq, &info);
217321
}
218322

219-
int its_init_v4(struct irq_domain *domain, const struct irq_domain_ops *ops)
323+
int its_prop_update_vsgi(int irq, u8 priority, bool group)
324+
{
325+
struct its_cmd_info info = {
326+
.cmd_type = PROP_UPDATE_VSGI,
327+
{
328+
.priority = priority,
329+
.group = group,
330+
},
331+
};
332+
333+
return irq_set_vcpu_affinity(irq, &info);
334+
}
335+
336+
int its_init_v4(struct irq_domain *domain,
337+
const struct irq_domain_ops *vpe_ops,
338+
const struct irq_domain_ops *sgi_ops)
220339
{
221340
if (domain) {
222341
pr_info("ITS: Enabling GICv4 support\n");
223342
gic_domain = domain;
224-
vpe_domain_ops = ops;
343+
vpe_domain_ops = vpe_ops;
344+
sgi_domain_ops = sgi_ops;
225345
return 0;
226346
}
227347

include/kvm/arm_vgic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ struct vgic_global {
7070

7171
/* Hardware has GICv4? */
7272
bool has_gicv4;
73+
bool has_gicv4_1;
7374

7475
/* GIC system register CPU interface */
7576
struct static_key_false gicv3_cpuif;

include/linux/irqchip/arm-gic-common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ struct gic_kvm_info {
3232
struct resource vctrl;
3333
/* vlpi support */
3434
bool has_v4;
35+
/* rvpeid support */
36+
bool has_v4_1;
3537
};
3638

3739
const struct gic_kvm_info *gic_get_kvm_info(void);

include/linux/irqchip/arm-gic-v3.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#define GICD_SPENDSGIR 0x0F20
5858

5959
#define GICD_CTLR_RWP (1U << 31)
60+
#define GICD_CTLR_nASSGIreq (1U << 8)
6061
#define GICD_CTLR_DS (1U << 6)
6162
#define GICD_CTLR_ARE_NS (1U << 4)
6263
#define GICD_CTLR_ENABLE_G1A (1U << 1)
@@ -90,6 +91,7 @@
9091
#define GICD_TYPER_ESPIS(typer) \
9192
(((typer) & GICD_TYPER_ESPI) ? GICD_TYPER_SPIS((typer) >> 27) : 0)
9293

94+
#define GICD_TYPER2_nASSGIcap (1U << 8)
9395
#define GICD_TYPER2_VIL (1U << 7)
9496
#define GICD_TYPER2_VID GENMASK(4, 0)
9597

@@ -346,6 +348,15 @@
346348
#define GICR_VPENDBASER_4_1_VGRP1EN (1ULL << 58)
347349
#define GICR_VPENDBASER_4_1_VPEID GENMASK_ULL(15, 0)
348350

351+
#define GICR_VSGIR 0x0080
352+
353+
#define GICR_VSGIR_VPEID GENMASK(15, 0)
354+
355+
#define GICR_VSGIPENDR 0x0088
356+
357+
#define GICR_VSGIPENDR_BUSY (1U << 31)
358+
#define GICR_VSGIPENDR_PENDING GENMASK(15, 0)
359+
349360
/*
350361
* ITS registers, offsets from ITS_base
351362
*/
@@ -369,6 +380,11 @@
369380

370381
#define GITS_TRANSLATER 0x10040
371382

383+
#define GITS_SGIR 0x20020
384+
385+
#define GITS_SGIR_VPEID GENMASK_ULL(47, 32)
386+
#define GITS_SGIR_VINTID GENMASK_ULL(3, 0)
387+
372388
#define GITS_CTLR_ENABLE (1U << 0)
373389
#define GITS_CTLR_ImDe (1U << 1)
374390
#define GITS_CTLR_ITS_NUMBER_SHIFT 4
@@ -503,8 +519,9 @@
503519
#define GITS_CMD_VMAPTI GITS_CMD_GICv4(GITS_CMD_MAPTI)
504520
#define GITS_CMD_VMOVI GITS_CMD_GICv4(GITS_CMD_MOVI)
505521
#define GITS_CMD_VSYNC GITS_CMD_GICv4(GITS_CMD_SYNC)
506-
/* VMOVP and INVDB are the odd ones, as they dont have a physical counterpart */
522+
/* VMOVP, VSGI and INVDB are the odd ones, as they dont have a physical counterpart */
507523
#define GITS_CMD_VMOVP GITS_CMD_GICv4(2)
524+
#define GITS_CMD_VSGI GITS_CMD_GICv4(3)
508525
#define GITS_CMD_INVDB GITS_CMD_GICv4(0xe)
509526

510527
/*
@@ -653,6 +670,7 @@
653670

654671
struct rdists {
655672
struct {
673+
raw_spinlock_t rd_lock;
656674
void __iomem *rd_base;
657675
struct page *pend_page;
658676
phys_addr_t phys_base;

include/linux/irqchip/arm-gic-v4.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,22 @@ struct its_vpe {
4949
};
5050
/* GICv4.1 implementations */
5151
struct {
52+
struct fwnode_handle *fwnode;
53+
struct irq_domain *sgi_domain;
54+
struct {
55+
u8 priority;
56+
bool enabled;
57+
bool group;
58+
} sgi_config[16];
5259
atomic_t vmapp_count;
5360
};
5461
};
5562

63+
/*
64+
* Ensures mutual exclusion between affinity setting of the
65+
* vPE and vLPI operations using vpe->col_idx.
66+
*/
67+
raw_spinlock_t vpe_lock;
5668
/*
5769
* This collection ID is used to indirect the target
5870
* redistributor for this VPE. The ID itself isn't involved in
@@ -93,6 +105,7 @@ enum its_vcpu_info_cmd_type {
93105
SCHEDULE_VPE,
94106
DESCHEDULE_VPE,
95107
INVALL_VPE,
108+
PROP_UPDATE_VSGI,
96109
};
97110

98111
struct its_cmd_info {
@@ -105,19 +118,27 @@ struct its_cmd_info {
105118
bool g0en;
106119
bool g1en;
107120
};
121+
struct {
122+
u8 priority;
123+
bool group;
124+
};
108125
};
109126
};
110127

111128
int its_alloc_vcpu_irqs(struct its_vm *vm);
112129
void its_free_vcpu_irqs(struct its_vm *vm);
113-
int its_schedule_vpe(struct its_vpe *vpe, bool on);
130+
int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en);
131+
int its_make_vpe_non_resident(struct its_vpe *vpe, bool db);
114132
int its_invall_vpe(struct its_vpe *vpe);
115133
int its_map_vlpi(int irq, struct its_vlpi_map *map);
116134
int its_get_vlpi(int irq, struct its_vlpi_map *map);
117135
int its_unmap_vlpi(int irq);
118136
int its_prop_update_vlpi(int irq, u8 config, bool inv);
137+
int its_prop_update_vsgi(int irq, u8 priority, bool group);
119138

120139
struct irq_domain_ops;
121-
int its_init_v4(struct irq_domain *domain, const struct irq_domain_ops *ops);
140+
int its_init_v4(struct irq_domain *domain,
141+
const struct irq_domain_ops *vpe_ops,
142+
const struct irq_domain_ops *sgi_ops);
122143

123144
#endif

virt/kvm/arm/vgic/vgic-v3.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,9 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
595595
/* GICv4 support? */
596596
if (info->has_v4) {
597597
kvm_vgic_global_state.has_gicv4 = gicv4_enable;
598-
kvm_info("GICv4 support %sabled\n",
598+
kvm_vgic_global_state.has_gicv4_1 = info->has_v4_1 && gicv4_enable;
599+
kvm_info("GICv4%s support %sabled\n",
600+
kvm_vgic_global_state.has_gicv4_1 ? ".1" : "",
599601
gicv4_enable ? "en" : "dis");
600602
}
601603

0 commit comments

Comments
 (0)