Skip to content

Commit 5c4d9ee

Browse files
KAGA-KOKOgregkh
authored andcommitted
genirq/affinity: Make affinity setting if activated opt-in
commit f0c7bac upstream. John reported that on a RK3288 system the perf per CPU interrupts are all affine to CPU0 and provided the analysis: "It looks like what happens is that because the interrupts are not per-CPU in the hardware, armpmu_request_irq() calls irq_force_affinity() while the interrupt is deactivated and then request_irq() with IRQF_PERCPU | IRQF_NOBALANCING. Now when irq_startup() runs with IRQ_STARTUP_NORMAL, it calls irq_setup_affinity() which returns early because IRQF_PERCPU and IRQF_NOBALANCING are set, leaving the interrupt on its original CPU." This was broken by the recent commit which blocked interrupt affinity setting in hardware before activation of the interrupt. While this works in general, it does not work for this particular case. As contrary to the initial analysis not all interrupt chip drivers implement an activate callback, the safe cure is to make the deferred interrupt affinity setting at activation time opt-in. Implement the necessary core logic and make the two irqchip implementations for which this is required opt-in. In hindsight this would have been the right thing to do, but ... Fixes: baedb87 ("genirq/affinity: Handle affinity setting on inactive interrupts correctly") Reported-by: John Keeping <john@metanate.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Marc Zyngier <maz@kernel.org> Acked-by: Marc Zyngier <maz@kernel.org> Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/87blk4tzgm.fsf@nanos.tec.linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent f4d8494 commit 5c4d9ee

4 files changed

Lines changed: 26 additions & 2 deletions

File tree

arch/x86/kernel/apic/vector.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,10 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
556556
irqd->chip_data = apicd;
557557
irqd->hwirq = virq + i;
558558
irqd_set_single_target(irqd);
559+
560+
/* Don't invoke affinity setter on deactivated interrupts */
561+
irqd_set_affinity_on_activate(irqd);
562+
559563
/*
560564
* Legacy vectors are already assigned when the IOAPIC
561565
* takes them over. They stay on the same vector. This is

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2458,6 +2458,7 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
24582458
{
24592459
msi_alloc_info_t *info = args;
24602460
struct its_device *its_dev = info->scratchpad[0].ptr;
2461+
struct irq_data *irqd;
24612462
irq_hw_number_t hwirq;
24622463
int err;
24632464
int i;
@@ -2473,7 +2474,9 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
24732474

24742475
irq_domain_set_hwirq_and_chip(domain, virq + i,
24752476
hwirq + i, &its_irq_chip, its_dev);
2476-
irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq + i)));
2477+
irqd = irq_get_irq_data(virq + i);
2478+
irqd_set_single_target(irqd);
2479+
irqd_set_affinity_on_activate(irqd);
24772480
pr_debug("ID:%d pID:%d vID:%d\n",
24782481
(int)(hwirq + i - its_dev->event_map.lpi_base),
24792482
(int)(hwirq + i), virq + i);

include/linux/irq.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ struct irq_data {
210210
* IRQD_CAN_RESERVE - Can use reservation mode
211211
* IRQD_MSI_NOMASK_QUIRK - Non-maskable MSI quirk for affinity change
212212
* required
213+
* IRQD_AFFINITY_ON_ACTIVATE - Affinity is set on activation. Don't call
214+
* irq_chip::irq_set_affinity() when deactivated.
213215
*/
214216
enum {
215217
IRQD_TRIGGER_MASK = 0xf,
@@ -233,6 +235,7 @@ enum {
233235
IRQD_DEFAULT_TRIGGER_SET = (1 << 25),
234236
IRQD_CAN_RESERVE = (1 << 26),
235237
IRQD_MSI_NOMASK_QUIRK = (1 << 27),
238+
IRQD_AFFINITY_ON_ACTIVATE = (1 << 29),
236239
};
237240

238241
#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)
@@ -407,6 +410,16 @@ static inline bool irqd_msi_nomask_quirk(struct irq_data *d)
407410
return __irqd_to_state(d) & IRQD_MSI_NOMASK_QUIRK;
408411
}
409412

413+
static inline void irqd_set_affinity_on_activate(struct irq_data *d)
414+
{
415+
__irqd_to_state(d) |= IRQD_AFFINITY_ON_ACTIVATE;
416+
}
417+
418+
static inline bool irqd_affinity_on_activate(struct irq_data *d)
419+
{
420+
return __irqd_to_state(d) & IRQD_AFFINITY_ON_ACTIVATE;
421+
}
422+
410423
#undef __irqd_to_state
411424

412425
static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)

kernel/irq/manage.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,16 @@ static bool irq_set_affinity_deactivated(struct irq_data *data,
280280
struct irq_desc *desc = irq_data_to_desc(data);
281281

282282
/*
283+
* Handle irq chips which can handle affinity only in activated
284+
* state correctly
285+
*
283286
* If the interrupt is not yet activated, just store the affinity
284287
* mask and do not call the chip driver at all. On activation the
285288
* driver has to make sure anyway that the interrupt is in a
286289
* useable state so startup works.
287290
*/
288-
if (!IS_ENABLED(CONFIG_IRQ_DOMAIN_HIERARCHY) || irqd_is_activated(data))
291+
if (!IS_ENABLED(CONFIG_IRQ_DOMAIN_HIERARCHY) ||
292+
irqd_is_activated(data) || !irqd_affinity_on_activate(data))
289293
return false;
290294

291295
cpumask_copy(desc->irq_common_data.affinity, mask);

0 commit comments

Comments
 (0)