To implement the get/set_irqchip_state callbacks (limited to the PENDING state), we have to use a particular set of hacks: - Reading the pending state is done by using a pair of new redistributor registers (GICR_VSGIR, GICR_VSGIPENDR), which allow the 16 interrupts state to be retrieved. - Setting the pending state is done by generating it as we'd otherwise do for a guest (writing to GITS_SGIR). - Clearing the pending state is done by emitting a VSGI command with the "clear" bit set. This requires some interesting locking though: - When talking to the redistributor, we must make sure that the VPE affinity doesn't change, hence taking the VPE lock. - At the same time, we must ensure that nobody accesses the same redistributor's GICR_VSGIR registers for a different VPE, which would corrupt the reading of the pending bits. We thus take the per-RD spinlock. Much fun.
Unified · Split
| @@ -3972,11 +3972,88 @@ static int its_sgi_set_affinity(struct irq_data *d, · 3971 unmodified lines | |||
| 3972 | return IRQ_SET_MASK_OK; | 3972 | return IRQ_SET_MASK_OK; |
| 3973 | } | 3973 | } |
| 3974 | 3974 | ||
| 3975 | static int its_sgi_set_irqchip_state(struct irq_data *d, | ||
| 3976 | enum irqchip_irq_state which, | ||
| 3977 | bool state) | ||
| 3978 | { | ||
| 3979 | if (which != IRQCHIP_STATE_PENDING) | ||
| 3980 | return -EINVAL; | ||
| 3981 | |||
| 3982 | if (state) { | ||
| 3983 | struct its_vpe *vpe = irq_data_get_irq_chip_data(d); | ||
| 3984 | struct its_node *its = find_4_1_its(); | ||
| 3985 | u64 val; | ||
| 3986 | |||
| 3987 | val = FIELD_PREP(GITS_SGIR_VPEID, vpe->vpe_id); | ||
| 3988 | val |= FIELD_PREP(GITS_SGIR_VINTID, d->hwirq); | ||
| 3989 | writeq_relaxed(val, its->sgir_base + GITS_SGIR - SZ_128K); | ||
| 3990 | } else { | ||
| 3991 | its_configure_sgi(d, true); | ||
| 3992 | } | ||
| 3993 | |||
| 3994 | return 0; | ||
| 3995 | } | ||
| 3996 | |||
| 3997 | static int its_sgi_get_irqchip_state(struct irq_data *d, | ||
| 3998 | enum irqchip_irq_state which, bool *val) | ||
| 3999 | { | ||
| 4000 | struct its_vpe *vpe = irq_data_get_irq_chip_data(d); | ||
| 4001 | void __iomem *base; | ||
| 4002 | unsigned long flags; | ||
| 4003 | u32 count = 1000000; /* 1s! */ | ||
| 4004 | u32 status; | ||
| 4005 | int cpu; | ||
| 4006 | |||
| 4007 | if (which != IRQCHIP_STATE_PENDING) | ||
| 4008 | return -EINVAL; | ||
| 4009 | |||
| 4010 | /* | ||
| 4011 | * Locking galore! We can race against two different events: | ||
| 4012 | * | ||
| 4013 | * - Concurent vPE affinity change: we must make sure it cannot | ||
| 4014 | * happen, or we'll talk to the wrong redistributor. This is | ||
| 4015 | * identical to what happens with vLPIs. | ||
| 4016 | * | ||
| 4017 | * - Concurrent VSGIPENDR access: As it involves accessing two | ||
| 4018 | * MMIO registers, this must be made atomic one way or another. | ||
| 4019 | */ | ||
| 4020 | cpu = vpe_to_cpuid_lock(vpe, &flags); | ||
| 4021 | raw_spin_lock(&gic_data_rdist_cpu(cpu)->rd_lock); | ||
| 4022 | base = gic_data_rdist_cpu(cpu)->rd_base + SZ_128K; | ||
| 4023 | writel_relaxed(vpe->vpe_id, base + GICR_VSGIR); | ||
| 4024 | do { | ||
| 4025 | status = readl_relaxed(base + GICR_VSGIPENDR); | ||
| 4026 | if (!(status & GICR_VSGIPENDR_BUSY)) | ||
| 4027 | goto out; | ||
| 4028 | |||
| 4029 | count--; | ||
| 4030 | if (!count) { | ||
| 4031 | pr_err_ratelimited("Unable to get SGI status\n"); | ||
| 4032 | goto out; | ||
| 4033 | } | ||
| 4034 | cpu_relax(); | ||
| 4035 | udelay(1); | ||
| 4036 | } while (count); | ||
| 4037 | |||
| 4038 | out: | ||
| 4039 | raw_spin_unlock(&gic_data_rdist_cpu(cpu)->rd_lock); | ||
| 4040 | vpe_to_cpuid_unlock(vpe, flags); | ||
| 4041 | |||
| 4042 | if (!count) | ||
| 4043 | return -ENXIO; | ||
| 4044 | |||
| 4045 | *val = !!(status & (1 << d->hwirq)); | ||
| 4046 | |||
| 4047 | return 0; | ||
| 4048 | } | ||
| 4049 | |||
| 3975 | static struct irq_chip its_sgi_irq_chip = { | 4050 | static struct irq_chip its_sgi_irq_chip = { |
| 3976 | .name = "GICv4.1-sgi", | 4051 | .name = "GICv4.1-sgi", |
| 3977 | .irq_mask = its_sgi_mask_irq, | 4052 | .irq_mask = its_sgi_mask_irq, |
| 3978 | .irq_unmask = its_sgi_unmask_irq, | 4053 | .irq_unmask = its_sgi_unmask_irq, |
| 3979 | .irq_set_affinity = its_sgi_set_affinity, | 4054 | .irq_set_affinity = its_sgi_set_affinity, |
| 4055 | .irq_set_irqchip_state = its_sgi_set_irqchip_state, | ||
| 4056 | .irq_get_irqchip_state = its_sgi_get_irqchip_state, | ||
| 3980 | }; | 4057 | }; |
| 3981 | 4058 | ||
| 3982 | static int its_sgi_irq_domain_alloc(struct irq_domain *domain, | 4059 | static int its_sgi_irq_domain_alloc(struct irq_domain *domain, |
| @@ -345,6 +345,15 @@ · 344 unmodified lines | |||
| 345 | #define GICR_VPENDBASER_4_1_VGRP1EN (1ULL << 58) | 345 | #define GICR_VPENDBASER_4_1_VGRP1EN (1ULL << 58) |
| 346 | #define GICR_VPENDBASER_4_1_VPEID GENMASK_ULL(15, 0) | 346 | #define GICR_VPENDBASER_4_1_VPEID GENMASK_ULL(15, 0) |
| 347 | 347 | ||
| 348 | #define GICR_VSGIR 0x0080 | ||
| 349 | |||
| 350 | #define GICR_VSGIR_VPEID GENMASK(15, 0) | ||
| 351 | |||
| 352 | #define GICR_VSGIPENDR 0x0088 | ||
| 353 | |||
| 354 | #define GICR_VSGIPENDR_BUSY (1U << 31) | ||
| 355 | #define GICR_VSGIPENDR_PENDING GENMASK(15, 0) | ||
| 356 | |||
| 348 | /* | 357 | /* |
| 349 | * ITS registers, offsets from ITS_base | 358 | * ITS registers, offsets from ITS_base |
| 350 | */ | 359 | */ |
| @@ -368,6 +377,11 @@ · 17 unmodified lines | |||
| 368 | 377 | ||
| 369 | #define GITS_TRANSLATER 0x10040 | 378 | #define GITS_TRANSLATER 0x10040 |
| 370 | 379 | ||
| 380 | #define GITS_SGIR 0x20020 | ||
| 381 | |||
| 382 | #define GITS_SGIR_VPEID GENMASK_ULL(47, 32) | ||
| 383 | #define GITS_SGIR_VINTID GENMASK_ULL(3, 0) | ||
| 384 | |||
| 371 | #define GITS_CTLR_ENABLE (1U << 0) | 385 | #define GITS_CTLR_ENABLE (1U << 0) |
| 372 | #define GITS_CTLR_ImDe (1U << 1) | 386 | #define GITS_CTLR_ImDe (1U << 1) |
| 373 | #define GITS_CTLR_ITS_NUMBER_SHIFT 4 | 387 | #define GITS_CTLR_ITS_NUMBER_SHIFT 4 |