Skip to content

Commit 9680622

Browse files
author
Marc Zyngier
committed
irqchip/gic-v4.1: Add support for VPENDBASER's Dirty+Valid signaling
When a vPE is made resident, the GIC starts parsing the virtual pending table to deliver pending interrupts. This takes place asynchronously, and can at times take a long while. Long enough that the vcpu enters the guest and hits WFI before any interrupt has been signaled yet. The vcpu then exits, blocks, and now gets a doorbell. Rince, repeat. In order to avoid the above, a (optional on GICv4, mandatory on v4.1) feature allows the GIC to feedback to the hypervisor whether it is done parsing the VPT by clearing the GICR_VPENDBASER.Dirty bit. The hypervisor can then wait until the GIC is ready before actually running the vPE. Plug the detection code as well as polling on vPE schedule. While at it, tidy-up the kernel message that displays the GICv4 optional features. Reviewed-by: Zenghui Yu <[email protected]> Signed-off-by: Marc Zyngier <[email protected]>
1 parent 8f3d9f3 commit 9680622

File tree

3 files changed

+28
-4
lines changed

3 files changed

+28
-4
lines changed

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/dma-iommu.h>
1515
#include <linux/efi.h>
1616
#include <linux/interrupt.h>
17+
#include <linux/iopoll.h>
1718
#include <linux/irqdomain.h>
1819
#include <linux/list.h>
1920
#include <linux/log2.h>
@@ -3672,6 +3673,20 @@ static int its_vpe_set_affinity(struct irq_data *d,
36723673
return IRQ_SET_MASK_OK_DONE;
36733674
}
36743675

3676+
static void its_wait_vpt_parse_complete(void)
3677+
{
3678+
void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
3679+
u64 val;
3680+
3681+
if (!gic_rdists->has_vpend_valid_dirty)
3682+
return;
3683+
3684+
WARN_ON_ONCE(readq_relaxed_poll_timeout(vlpi_base + GICR_VPENDBASER,
3685+
val,
3686+
!(val & GICR_VPENDBASER_Dirty),
3687+
10, 500));
3688+
}
3689+
36753690
static void its_vpe_schedule(struct its_vpe *vpe)
36763691
{
36773692
void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
@@ -3702,6 +3717,8 @@ static void its_vpe_schedule(struct its_vpe *vpe)
37023717
val |= vpe->idai ? GICR_VPENDBASER_IDAI : 0;
37033718
val |= GICR_VPENDBASER_Valid;
37043719
gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
3720+
3721+
its_wait_vpt_parse_complete();
37053722
}
37063723

37073724
static void its_vpe_deschedule(struct its_vpe *vpe)
@@ -3910,6 +3927,8 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe,
39103927
val |= FIELD_PREP(GICR_VPENDBASER_4_1_VPEID, vpe->vpe_id);
39113928

39123929
gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
3930+
3931+
its_wait_vpt_parse_complete();
39133932
}
39143933

39153934
static void its_vpe_4_1_deschedule(struct its_vpe *vpe,

drivers/irqchip/irq-gic-v3.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,7 @@ static int __gic_update_rdist_properties(struct redist_region *region,
873873
gic_data.rdists.has_rvpeid &= !!(typer & GICR_TYPER_RVPEID);
874874
gic_data.rdists.has_direct_lpi &= (!!(typer & GICR_TYPER_DirectLPIS) |
875875
gic_data.rdists.has_rvpeid);
876+
gic_data.rdists.has_vpend_valid_dirty &= !!(typer & GICR_TYPER_DIRTY);
876877

877878
/* Detect non-sensical configurations */
878879
if (WARN_ON_ONCE(gic_data.rdists.has_rvpeid && !gic_data.rdists.has_vlpis)) {
@@ -893,10 +894,11 @@ static void gic_update_rdist_properties(void)
893894
if (WARN_ON(gic_data.ppi_nr == UINT_MAX))
894895
gic_data.ppi_nr = 0;
895896
pr_info("%d PPIs implemented\n", gic_data.ppi_nr);
896-
pr_info("%sVLPI support, %sdirect LPI support, %sRVPEID support\n",
897-
!gic_data.rdists.has_vlpis ? "no " : "",
898-
!gic_data.rdists.has_direct_lpi ? "no " : "",
899-
!gic_data.rdists.has_rvpeid ? "no " : "");
897+
if (gic_data.rdists.has_vlpis)
898+
pr_info("GICv4 features: %s%s%s\n",
899+
gic_data.rdists.has_direct_lpi ? "DirectLPI " : "",
900+
gic_data.rdists.has_rvpeid ? "RVPEID " : "",
901+
gic_data.rdists.has_vpend_valid_dirty ? "Valid+Dirty " : "");
900902
}
901903

902904
/* Check whether it's single security state view */
@@ -1620,6 +1622,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
16201622
gic_data.rdists.has_rvpeid = true;
16211623
gic_data.rdists.has_vlpis = true;
16221624
gic_data.rdists.has_direct_lpi = true;
1625+
gic_data.rdists.has_vpend_valid_dirty = true;
16231626

16241627
if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
16251628
err = -ENOMEM;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@
243243

244244
#define GICR_TYPER_PLPIS (1U << 0)
245245
#define GICR_TYPER_VLPIS (1U << 1)
246+
#define GICR_TYPER_DIRTY (1U << 2)
246247
#define GICR_TYPER_DirectLPIS (1U << 3)
247248
#define GICR_TYPER_LAST (1U << 4)
248249
#define GICR_TYPER_RVPEID (1U << 7)
@@ -686,6 +687,7 @@ struct rdists {
686687
bool has_vlpis;
687688
bool has_rvpeid;
688689
bool has_direct_lpi;
690+
bool has_vpend_valid_dirty;
689691
};
690692

691693
struct irq_domain;

0 commit comments

Comments
 (0)