Skip to content

Commit e643d80

Browse files
author
Marc Zyngier
committed
irqchip/gic-v3-its: Add VPE scheduling
When a VPE is scheduled to run, the corresponding redistributor must be told so, by setting VPROPBASER to the VM's property table, and VPENDBASER to the vcpu's pending table. When scheduled out, we preserve the IDAI and PendingLast bits. The latter is specially important, as it tells the hypervisor that there are pending interrupts for this vcpu. Reviewed-by: Eric Auger <eric.auger@redhat.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent 3ca63f3 commit e643d80

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

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

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ static DEFINE_IDA(its_vpeid_ida);
152152

153153
#define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist))
154154
#define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base)
155+
#define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K)
155156

156157
static struct its_collection *dev_event_to_col(struct its_device *its_dev,
157158
u32 event)
@@ -2153,8 +2154,92 @@ static const struct irq_domain_ops its_domain_ops = {
21532154
.deactivate = its_irq_domain_deactivate,
21542155
};
21552156

2157+
static void its_vpe_schedule(struct its_vpe *vpe)
2158+
{
2159+
void * __iomem vlpi_base = gic_data_rdist_vlpi_base();
2160+
u64 val;
2161+
2162+
/* Schedule the VPE */
2163+
val = virt_to_phys(page_address(vpe->its_vm->vprop_page)) &
2164+
GENMASK_ULL(51, 12);
2165+
val |= (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK;
2166+
val |= GICR_VPROPBASER_RaWb;
2167+
val |= GICR_VPROPBASER_InnerShareable;
2168+
gits_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
2169+
2170+
val = virt_to_phys(page_address(vpe->vpt_page)) &
2171+
GENMASK_ULL(51, 16);
2172+
val |= GICR_VPENDBASER_RaWaWb;
2173+
val |= GICR_VPENDBASER_NonShareable;
2174+
/*
2175+
* There is no good way of finding out if the pending table is
2176+
* empty as we can race against the doorbell interrupt very
2177+
* easily. So in the end, vpe->pending_last is only an
2178+
* indication that the vcpu has something pending, not one
2179+
* that the pending table is empty. A good implementation
2180+
* would be able to read its coarse map pretty quickly anyway,
2181+
* making this a tolerable issue.
2182+
*/
2183+
val |= GICR_VPENDBASER_PendingLast;
2184+
val |= vpe->idai ? GICR_VPENDBASER_IDAI : 0;
2185+
val |= GICR_VPENDBASER_Valid;
2186+
gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
2187+
}
2188+
2189+
static void its_vpe_deschedule(struct its_vpe *vpe)
2190+
{
2191+
void * __iomem vlpi_base = gic_data_rdist_vlpi_base();
2192+
u32 count = 1000000; /* 1s! */
2193+
bool clean;
2194+
u64 val;
2195+
2196+
/* We're being scheduled out */
2197+
val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2198+
val &= ~GICR_VPENDBASER_Valid;
2199+
gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
2200+
2201+
do {
2202+
val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2203+
clean = !(val & GICR_VPENDBASER_Dirty);
2204+
if (!clean) {
2205+
count--;
2206+
cpu_relax();
2207+
udelay(1);
2208+
}
2209+
} while (!clean && count);
2210+
2211+
if (unlikely(!clean && !count)) {
2212+
pr_err_ratelimited("ITS virtual pending table not cleaning\n");
2213+
vpe->idai = false;
2214+
vpe->pending_last = true;
2215+
} else {
2216+
vpe->idai = !!(val & GICR_VPENDBASER_IDAI);
2217+
vpe->pending_last = !!(val & GICR_VPENDBASER_PendingLast);
2218+
}
2219+
}
2220+
2221+
static int its_vpe_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
2222+
{
2223+
struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
2224+
struct its_cmd_info *info = vcpu_info;
2225+
2226+
switch (info->cmd_type) {
2227+
case SCHEDULE_VPE:
2228+
its_vpe_schedule(vpe);
2229+
return 0;
2230+
2231+
case DESCHEDULE_VPE:
2232+
its_vpe_deschedule(vpe);
2233+
return 0;
2234+
2235+
default:
2236+
return -EINVAL;
2237+
}
2238+
}
2239+
21562240
static struct irq_chip its_vpe_irq_chip = {
21572241
.name = "GICv4-vpe",
2242+
.irq_set_vcpu_affinity = its_vpe_set_vcpu_affinity,
21582243
};
21592244

21602245
static int its_vpe_id_alloc(void)

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,64 @@
212212
#define LPI_PROP_GROUP1 (1 << 1)
213213
#define LPI_PROP_ENABLED (1 << 0)
214214

215+
/*
216+
* Re-Distributor registers, offsets from VLPI_base
217+
*/
218+
#define GICR_VPROPBASER 0x0070
219+
220+
#define GICR_VPROPBASER_IDBITS_MASK 0x1f
221+
222+
#define GICR_VPROPBASER_SHAREABILITY_SHIFT (10)
223+
#define GICR_VPROPBASER_INNER_CACHEABILITY_SHIFT (7)
224+
#define GICR_VPROPBASER_OUTER_CACHEABILITY_SHIFT (56)
225+
226+
#define GICR_VPROPBASER_SHAREABILITY_MASK \
227+
GIC_BASER_SHAREABILITY(GICR_VPROPBASER, SHAREABILITY_MASK)
228+
#define GICR_VPROPBASER_INNER_CACHEABILITY_MASK \
229+
GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, MASK)
230+
#define GICR_VPROPBASER_OUTER_CACHEABILITY_MASK \
231+
GIC_BASER_CACHEABILITY(GICR_VPROPBASER, OUTER, MASK)
232+
#define GICR_VPROPBASER_CACHEABILITY_MASK \
233+
GICR_VPROPBASER_INNER_CACHEABILITY_MASK
234+
235+
#define GICR_VPROPBASER_InnerShareable \
236+
GIC_BASER_SHAREABILITY(GICR_VPROPBASER, InnerShareable)
237+
238+
#define GICR_VPROPBASER_nCnB GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, nCnB)
239+
#define GICR_VPROPBASER_nC GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, nC)
240+
#define GICR_VPROPBASER_RaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWt)
241+
#define GICR_VPROPBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWt)
242+
#define GICR_VPROPBASER_WaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, WaWt)
243+
#define GICR_VPROPBASER_WaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, WaWb)
244+
#define GICR_VPROPBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWaWt)
245+
#define GICR_VPROPBASER_RaWaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWaWb)
246+
247+
#define GICR_VPENDBASER 0x0078
248+
249+
#define GICR_VPENDBASER_SHAREABILITY_SHIFT (10)
250+
#define GICR_VPENDBASER_INNER_CACHEABILITY_SHIFT (7)
251+
#define GICR_VPENDBASER_OUTER_CACHEABILITY_SHIFT (56)
252+
#define GICR_VPENDBASER_SHAREABILITY_MASK \
253+
GIC_BASER_SHAREABILITY(GICR_VPENDBASER, SHAREABILITY_MASK)
254+
#define GICR_VPENDBASER_INNER_CACHEABILITY_MASK \
255+
GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, MASK)
256+
#define GICR_VPENDBASER_OUTER_CACHEABILITY_MASK \
257+
GIC_BASER_CACHEABILITY(GICR_VPENDBASER, OUTER, MASK)
258+
#define GICR_VPENDBASER_CACHEABILITY_MASK \
259+
GICR_VPENDBASER_INNER_CACHEABILITY_MASK
260+
261+
#define GICR_VPENDBASER_NonShareable \
262+
GIC_BASER_SHAREABILITY(GICR_VPENDBASER, NonShareable)
263+
264+
#define GICR_VPENDBASER_nCnB GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, nCnB)
265+
#define GICR_VPENDBASER_nC GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, nC)
266+
#define GICR_VPENDBASER_RaWt GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWt)
267+
#define GICR_VPENDBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWt)
268+
#define GICR_VPENDBASER_WaWt GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, WaWt)
269+
#define GICR_VPENDBASER_WaWb GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, WaWb)
270+
#define GICR_VPENDBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWaWt)
271+
#define GICR_VPENDBASER_RaWaWb GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWaWb)
272+
215273
#define GICR_VPENDBASER_Dirty (1ULL << 60)
216274
#define GICR_VPENDBASER_PendingLast (1ULL << 61)
217275
#define GICR_VPENDBASER_IDAI (1ULL << 62)

0 commit comments

Comments
 (0)