Commit c119e668 authored by Marc Zyngier's avatar Marc Zyngier Committed by Thomas Gleixner
Browse files

genirq: Remove IRQ timing tracking infrastructure



The IRQ timing tracking infrastructure was merged in 2019, but was never
plumbed in, is not selectable, and is therefore never used.

As Daniel agrees that there is little hope for this infrastructure to be
completed in the near term, drop it altogether.

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarJinjie Ruan <ruanjinjie@huawei.com>
Link: https://lore.kernel.org/r/87zf7vex6h.wl-maz@kernel.org
Link: https://patch.msgid.link/20251210082242.360936-2-maz@kernel.org
parent 8f0b4cce
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -871,12 +871,6 @@ static inline void init_irq_proc(void)
}
#endif

#ifdef CONFIG_IRQ_TIMINGS
void irq_timings_enable(void);
void irq_timings_disable(void);
u64 irq_timings_next_event(u64 now);
#endif

struct seq_file;
int show_interrupts(struct seq_file *p, void *v);
int arch_show_interrupts(struct seq_file *p, int prec);
+0 −3
Original line number Diff line number Diff line
@@ -92,9 +92,6 @@ config GENERIC_MSI_IRQ
config IRQ_MSI_IOMMU
	bool

config IRQ_TIMINGS
	bool

config GENERIC_IRQ_MATRIX_ALLOCATOR
	bool

+0 −4
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0

obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o kexec.o
obj-$(CONFIG_IRQ_TIMINGS) += timings.o
ifeq ($(CONFIG_TEST_IRQ_TIMINGS),y)
	CFLAGS_timings.o += -DDEBUG
endif
obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
+0 −2
Original line number Diff line number Diff line
@@ -188,8 +188,6 @@ irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc)
	unsigned int irq = desc->irq_data.irq;
	struct irqaction *action;

	record_irq_time(desc);

	for_each_action_of_desc(desc, action) {
		irqreturn_t res;

+0 −110
Original line number Diff line number Diff line
@@ -288,116 +288,6 @@ static inline void
irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) { }
#endif

#ifdef CONFIG_IRQ_TIMINGS

#define IRQ_TIMINGS_SHIFT	5
#define IRQ_TIMINGS_SIZE	(1 << IRQ_TIMINGS_SHIFT)
#define IRQ_TIMINGS_MASK	(IRQ_TIMINGS_SIZE - 1)

/**
 * struct irq_timings - irq timings storing structure
 * @values: a circular buffer of u64 encoded <timestamp,irq> values
 * @count: the number of elements in the array
 */
struct irq_timings {
	u64	values[IRQ_TIMINGS_SIZE];
	int	count;
};

DECLARE_PER_CPU(struct irq_timings, irq_timings);

extern void irq_timings_free(int irq);
extern int irq_timings_alloc(int irq);

static inline void irq_remove_timings(struct irq_desc *desc)
{
	desc->istate &= ~IRQS_TIMINGS;

	irq_timings_free(irq_desc_get_irq(desc));
}

static inline void irq_setup_timings(struct irq_desc *desc, struct irqaction *act)
{
	int irq = irq_desc_get_irq(desc);
	int ret;

	/*
	 * We don't need the measurement because the idle code already
	 * knows the next expiry event.
	 */
	if (act->flags & __IRQF_TIMER)
		return;

	/*
	 * In case the timing allocation fails, we just want to warn,
	 * not fail, so letting the system boot anyway.
	 */
	ret = irq_timings_alloc(irq);
	if (ret) {
		pr_warn("Failed to allocate irq timing stats for irq%d (%d)",
			irq, ret);
		return;
	}

	desc->istate |= IRQS_TIMINGS;
}

extern void irq_timings_enable(void);
extern void irq_timings_disable(void);

DECLARE_STATIC_KEY_FALSE(irq_timing_enabled);

/*
 * The interrupt number and the timestamp are encoded into a single
 * u64 variable to optimize the size.
 * 48 bit time stamp and 16 bit IRQ number is way sufficient.
 *  Who cares an IRQ after 78 hours of idle time?
 */
static inline u64 irq_timing_encode(u64 timestamp, int irq)
{
	return (timestamp << 16) | irq;
}

static inline int irq_timing_decode(u64 value, u64 *timestamp)
{
	*timestamp = value >> 16;
	return value & U16_MAX;
}

static __always_inline void irq_timings_push(u64 ts, int irq)
{
	struct irq_timings *timings = this_cpu_ptr(&irq_timings);

	timings->values[timings->count & IRQ_TIMINGS_MASK] =
		irq_timing_encode(ts, irq);

	timings->count++;
}

/*
 * The function record_irq_time is only called in one place in the
 * interrupts handler. We want this function always inline so the code
 * inside is embedded in the function and the static key branching
 * code can act at the higher level. Without the explicit
 * __always_inline we can end up with a function call and a small
 * overhead in the hotpath for nothing.
 */
static __always_inline void record_irq_time(struct irq_desc *desc)
{
	if (!static_branch_likely(&irq_timing_enabled))
		return;

	if (desc->istate & IRQS_TIMINGS)
		irq_timings_push(local_clock(), irq_desc_get_irq(desc));
}
#else
static inline void irq_remove_timings(struct irq_desc *desc) {}
static inline void irq_setup_timings(struct irq_desc *desc,
				     struct irqaction *act) {};
static inline void record_irq_time(struct irq_desc *desc) {}
#endif /* CONFIG_IRQ_TIMINGS */


#ifdef CONFIG_GENERIC_IRQ_CHIP
void irq_init_generic_chip(struct irq_chip_generic *gc, const char *name,
			   int num_ct, unsigned int irq_base,
Loading