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 | 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 | 4050 | static struct irq_chip its_sgi_irq_chip = { |
| 3976 | 4051 | .name = "GICv4.1-sgi", |
| 3977 | 4052 | .irq_mask = its_sgi_mask_irq, |
| 3978 | 4053 | .irq_unmask = its_sgi_unmask_irq, |
| 3979 | 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 | 4059 | static int its_sgi_irq_domain_alloc(struct irq_domain *domain, |
| @@ -345,6 +345,15 @@ · 344 unmodified lines | ||
| 345 | 345 | #define GICR_VPENDBASER_4_1_VGRP1EN (1ULL << 58) |
| 346 | 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 | 358 | * ITS registers, offsets from ITS_base |
| 350 | 359 | */ |
| @@ -368,6 +377,11 @@ · 17 unmodified lines | ||
| 368 | 377 | |
| 369 | 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 | 385 | #define GITS_CTLR_ENABLE (1U << 0) |
| 372 | 386 | #define GITS_CTLR_ImDe (1U << 1) |
| 373 | 387 | #define GITS_CTLR_ITS_NUMBER_SHIFT 4 |