summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2022-05-11 16:47:07 +0200
committerSebastian Andrzej Siewior <bigeasy@linutronix.de>2022-05-11 16:47:07 +0200
commitbcc43dc58987708e7f68c7a6bac57b92ef5722e8 (patch)
treec98d272c4395f01ab4760376ae311a2a228a8634
parent5ab3e4494dad3d2c934feb52cb3c5b28bb096109 (diff)
downloadlinux-rt-bcc43dc58987708e7f68c7a6bac57b92ef5722e8.tar.gz
[ANNOUNCE] v5.18-rc6-rt7v5.18-rc6-rt7-patches
Dear RT folks! I'm pleased to announce the v5.18-rc6-rt7 patch set. Changes since v5.18-rc6-rt6: - The irq simulator did not invoke the interrupts in hardirq context, as it should. - Provide generic_handle_domain_irq_safe(). It has been reported via the kernel bugzilla that the amd-pincrl driver reports interrupts in the wrong context. - rcutorture could miss pending timers because ktimers runs at the same priority as the rcutorture thread. Patch by Frederic Weisbecker. - Since the introduction of timersd in v5.16-rc3-rt7 there can be a in the NO_HZ mode. Patch by Frederic Weisbecker. - A small optimisation in iio's stm32-adc driver. - An unused macro in lockdep has been removed. Known issues - Valentin Schneider reported a few splats on ARM64, see https://lkml.kernel.org/r/20210810134127.1394269-1-valentin.schneider@arm.com The delta patch against v5.18-rc6-rt6 is appended below and can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.18/incr/patch-5.18-rc6-rt6-rt7.patch.xz You can get this release via the git tree at: git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v5.18-rc6-rt7 The RT patch against v5.18-rc6 can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.18/older/patch-5.18-rc6-rt7.patch.xz The split quilt queue is available at: https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.18/older/patches-5.18-rc6-rt7.tar.xz Sebastian Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-rw-r--r--patches/Add_localversion_for_-RT_release.patch2
-rw-r--r--patches/genirq-Provide-generic_handle_domain_irq_safe.patch152
-rw-r--r--patches/genirq-irq_sim-Make-the-irq_work-always-run-in-hard-.patch37
-rw-r--r--patches/iio-adc-stm32-adc-Use-generic_handle_domain_irq.patch35
-rw-r--r--patches/locking-lockdep-Remove-lockdep_init_map_crosslock.patch26
-rw-r--r--patches/rcutorture-Also-force-sched-priority-to-timersd-on-b.patch70
-rw-r--r--patches/series6
-rw-r--r--patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch105
8 files changed, 432 insertions, 1 deletions
diff --git a/patches/Add_localversion_for_-RT_release.patch b/patches/Add_localversion_for_-RT_release.patch
index 7b3d2414e699..e58a29adc4af 100644
--- a/patches/Add_localversion_for_-RT_release.patch
+++ b/patches/Add_localversion_for_-RT_release.patch
@@ -15,4 +15,4 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
--- /dev/null
+++ b/localversion-rt
@@ -0,0 +1 @@
-+-rt6
++-rt7
diff --git a/patches/genirq-Provide-generic_handle_domain_irq_safe.patch b/patches/genirq-Provide-generic_handle_domain_irq_safe.patch
new file mode 100644
index 000000000000..3deba9c63660
--- /dev/null
+++ b/patches/genirq-Provide-generic_handle_domain_irq_safe.patch
@@ -0,0 +1,152 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Mon, 9 May 2022 16:04:08 +0200
+Subject: [PATCH] genirq: Provide generic_handle_domain_irq_safe().
+
+Provide generic_handle_domain_irq_safe() which can used from any context.
+This similar to commit
+ 509853f9e1e7b ("genirq: Provide generic_handle_irq_safe()")
+
+but this time for the irq-domains interface. It has been reported for
+the amd-pinctrl driver via bugzilla
+ https://bugzilla.kernel.org/show_bug.cgi?id=215954
+
+I looked around and added a few users so it is not just one user API :)
+Instead of generic_handle_irq(irq_find_mapping)) one can use
+generic_handle_domain_irq().
+
+The problem with generic_handle_domain_irq() is that with `threadirqs'
+it will trigger "WARN_ON_ONCE(!in_hardirq())". That interrupt handler
+can't be marked non-threaded because it is a shared handler (it is
+marked as such and I can't tell the interrupt can be really shared on
+the system).
+Ignoring the just mentioned warning, on PREEMPT_RT the threaded handler
+is invoked with enabled interrupts leading other problems.
+
+Do we do this?
+
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/YnkfWFzvusFFktSt@linutronix.de
+---
+ drivers/bcma/driver_gpio.c | 2 +-
+ drivers/gpio/gpio-mlxbf2.c | 6 ++----
+ drivers/pinctrl/pinctrl-amd.c | 2 +-
+ drivers/platform/x86/intel/int0002_vgpio.c | 3 +--
+ drivers/ssb/driver_gpio.c | 6 ++++--
+ include/linux/irqdesc.h | 1 +
+ kernel/irq/irqdesc.c | 24 ++++++++++++++++++++++++
+ 7 files changed, 34 insertions(+), 10 deletions(-)
+
+--- a/drivers/bcma/driver_gpio.c
++++ b/drivers/bcma/driver_gpio.c
+@@ -113,7 +113,7 @@ static irqreturn_t bcma_gpio_irq_handler
+ return IRQ_NONE;
+
+ for_each_set_bit(gpio, &irqs, gc->ngpio)
+- generic_handle_irq(irq_find_mapping(gc->irq.domain, gpio));
++ generic_handle_domain_irq_safe(gc->irq.domain, gpio);
+ bcma_chipco_gpio_polarity(cc, irqs, val & irqs);
+
+ return IRQ_HANDLED;
+--- a/drivers/gpio/gpio-mlxbf2.c
++++ b/drivers/gpio/gpio-mlxbf2.c
+@@ -273,10 +273,8 @@ static irqreturn_t mlxbf2_gpio_irq_handl
+ pending = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0);
+ writel(pending, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
+
+- for_each_set_bit(level, &pending, gc->ngpio) {
+- int gpio_irq = irq_find_mapping(gc->irq.domain, level);
+- generic_handle_irq(gpio_irq);
+- }
++ for_each_set_bit(level, &pending, gc->ngpio)
++ generic_handle_domain_irq_safe(gc->irq.domain, level);
+
+ return IRQ_RETVAL(pending);
+ }
+--- a/drivers/pinctrl/pinctrl-amd.c
++++ b/drivers/pinctrl/pinctrl-amd.c
+@@ -638,7 +638,7 @@ static bool do_amd_gpio_irq_handler(int
+ if (!(regval & PIN_IRQ_PENDING) ||
+ !(regval & BIT(INTERRUPT_MASK_OFF)))
+ continue;
+- generic_handle_domain_irq(gc->irq.domain, irqnr + i);
++ generic_handle_domain_irq_safe(gc->irq.domain, irqnr + i);
+
+ /* Clear interrupt.
+ * We must read the pin register again, in case the
+--- a/drivers/platform/x86/intel/int0002_vgpio.c
++++ b/drivers/platform/x86/intel/int0002_vgpio.c
+@@ -125,8 +125,7 @@ static irqreturn_t int0002_irq(int irq,
+ if (!(gpe_sts_reg & GPE0A_PME_B0_STS_BIT))
+ return IRQ_NONE;
+
+- generic_handle_irq(irq_find_mapping(chip->irq.domain,
+- GPE0A_PME_B0_VIRT_GPIO_PIN));
++ generic_handle_domain_irq_safe(chip->irq.domain, GPE0A_PME_B0_VIRT_GPIO_PIN);
+
+ pm_wakeup_hard_event(chip->parent);
+
+--- a/drivers/ssb/driver_gpio.c
++++ b/drivers/ssb/driver_gpio.c
+@@ -132,7 +132,8 @@ static irqreturn_t ssb_gpio_irq_chipco_h
+ return IRQ_NONE;
+
+ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio)
+- generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio));
++ generic_handle_domain_irq_safe(bus->irq_domain, gpio);
++
+ ssb_chipco_gpio_polarity(chipco, irqs, val & irqs);
+
+ return IRQ_HANDLED;
+@@ -330,7 +331,8 @@ static irqreturn_t ssb_gpio_irq_extif_ha
+ return IRQ_NONE;
+
+ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio)
+- generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio));
++ generic_handle_domain_irq_safe(bus->irq_domain, gpio);
++
+ ssb_extif_gpio_polarity(extif, irqs, val & irqs);
+
+ return IRQ_HANDLED;
+--- a/include/linux/irqdesc.h
++++ b/include/linux/irqdesc.h
+@@ -169,6 +169,7 @@ int generic_handle_irq_safe(unsigned int
+ * conversion failed.
+ */
+ int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq);
++int generic_handle_domain_irq_safe(struct irq_domain *domain, unsigned int hwirq);
+ int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq);
+ #endif
+
+--- a/kernel/irq/irqdesc.c
++++ b/kernel/irq/irqdesc.c
+@@ -706,6 +706,30 @@ int generic_handle_domain_irq(struct irq
+ }
+ EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
+
++ /**
++ * generic_handle_irq_safe - Invoke the handler for a HW irq belonging
++ * to a domain from any context.
++ * @domain: The domain where to perform the lookup
++ * @hwirq: The HW irq number to convert to a logical one
++ *
++ * Returns: 0 on success, a negative value on error.
++ *
++ * This function can be called from any context (IRQ or process context). It
++ * will report an error if not invoked from IRQ context and the irq has been
++ * marked to enforce IRQ-context only.
++ */
++int generic_handle_domain_irq_safe(struct irq_domain *domain, unsigned int hwirq)
++{
++ unsigned long flags;
++ int ret;
++
++ local_irq_save(flags);
++ ret = handle_irq_desc(irq_resolve_mapping(domain, hwirq));
++ local_irq_restore(flags);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(generic_handle_domain_irq_safe);
++
+ /**
+ * generic_handle_domain_nmi - Invoke the handler for a HW nmi belonging
+ * to a domain.
diff --git a/patches/genirq-irq_sim-Make-the-irq_work-always-run-in-hard-.patch b/patches/genirq-irq_sim-Make-the-irq_work-always-run-in-hard-.patch
new file mode 100644
index 000000000000..d00e8b607af5
--- /dev/null
+++ b/patches/genirq-irq_sim-Make-the-irq_work-always-run-in-hard-.patch
@@ -0,0 +1,37 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Wed, 11 May 2022 13:07:50 +0200
+Subject: [PATCH] genirq/irq_sim: Make the irq_work always run in hard irq
+ context.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The IRQ simulator uses irq_work to trigger an interrupt. Without the
+IRQ_WORK_HARD_IRQ flag the irq_work will be performed in thread context
+on PREEMPT_RT. This causes locking errors later in handle_simple_irq()
+which expects to be invoked with disabled interrupts.
+
+Triggering individual interrupts in hardirq context should not lead to
+unexpected high latencies since this is also what the hardware
+controller does. Also it is used as a simulator so…
+
+Use IRQ_WORK_INIT_HARD() to carry out the irq_work in hardirq context on
+PREEMPT_RT.
+
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/YnuZBoEVMGwKkLm+@linutronix.de
+---
+ kernel/irq/irq_sim.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/kernel/irq/irq_sim.c
++++ b/kernel/irq/irq_sim.c
+@@ -181,7 +181,7 @@ struct irq_domain *irq_domain_create_sim
+ goto err_free_bitmap;
+
+ work_ctx->irq_count = num_irqs;
+- init_irq_work(&work_ctx->work, irq_sim_handle_irq);
++ work_ctx->work = IRQ_WORK_INIT_HARD(irq_sim_handle_irq);
+
+ return work_ctx->domain;
+
diff --git a/patches/iio-adc-stm32-adc-Use-generic_handle_domain_irq.patch b/patches/iio-adc-stm32-adc-Use-generic_handle_domain_irq.patch
new file mode 100644
index 000000000000..485c3e422fbd
--- /dev/null
+++ b/patches/iio-adc-stm32-adc-Use-generic_handle_domain_irq.patch
@@ -0,0 +1,35 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Wed, 11 May 2022 13:06:09 +0200
+Subject: [PATCH] iio: adc: stm32-adc: Use generic_handle_domain_irq()
+
+The call chain
+ generic_handle_irq(irq_find_mapping(domain, x));
+
+could be replaced with
+ generic_handle_domain_irq(domain, x);
+
+which looks up the struct irq_desc for the interrupt and handles it with
+handle_irq_desc().
+This is a slight optimisation given that the driver invokes only one
+function and the struct irq_desc is used directly instead being looked
+up via irq_to_desc().
+
+Use generic_handle_domain_irq().
+
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/YnuYoQIzJoFIyEJY@linutronix.de
+---
+ drivers/iio/adc/stm32-adc-core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/iio/adc/stm32-adc-core.c
++++ b/drivers/iio/adc/stm32-adc-core.c
+@@ -356,7 +356,7 @@ static void stm32_adc_irq_handler(struct
+ if ((status & priv->cfg->regs->eoc_msk[i] &&
+ stm32_adc_eoc_enabled(priv, i)) ||
+ (status & priv->cfg->regs->ovr_msk[i]))
+- generic_handle_irq(irq_find_mapping(priv->domain, i));
++ generic_handle_domain_irq(priv->domain, i);
+ }
+
+ chained_irq_exit(chip, desc);
diff --git a/patches/locking-lockdep-Remove-lockdep_init_map_crosslock.patch b/patches/locking-lockdep-Remove-lockdep_init_map_crosslock.patch
new file mode 100644
index 000000000000..92696439986d
--- /dev/null
+++ b/patches/locking-lockdep-Remove-lockdep_init_map_crosslock.patch
@@ -0,0 +1,26 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Fri, 11 Mar 2022 17:44:57 +0100
+Subject: [PATCH] locking/lockdep: Remove lockdep_init_map_crosslock.
+
+The cross-release bits have been removed, lockdep_init_map_crosslock() is
+a leftover.
+
+Remove lockdep_init_map_crosslock.
+
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Reviewed-by: Waiman Long <longman@redhat.com>
+Link: https://lore.kernel.org/r/20220311164457.46461-1-bigeasy@linutronix.de
+---
+ include/linux/lockdep.h | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/include/linux/lockdep.h
++++ b/include/linux/lockdep.h
+@@ -431,7 +431,6 @@ enum xhlock_context_t {
+ XHLOCK_CTX_NR,
+ };
+
+-#define lockdep_init_map_crosslock(m, n, k, s) do {} while (0)
+ /*
+ * To initialize a lockdep_map statically use this macro.
+ * Note that _name must not be NULL.
diff --git a/patches/rcutorture-Also-force-sched-priority-to-timersd-on-b.patch b/patches/rcutorture-Also-force-sched-priority-to-timersd-on-b.patch
new file mode 100644
index 000000000000..81388d4b14c5
--- /dev/null
+++ b/patches/rcutorture-Also-force-sched-priority-to-timersd-on-b.patch
@@ -0,0 +1,70 @@
+From: Frederic Weisbecker <frederic@kernel.org>
+Date: Tue, 5 Apr 2022 03:07:51 +0200
+Subject: [PATCH] rcutorture: Also force sched priority to timersd on
+ boosting test.
+
+ksoftirqd is statically boosted to the priority level right above the
+one of rcu_torture_boost() so that timers, which torture readers rely on,
+get a chance to run while rcu_torture_boost() is polling.
+
+However timers processing got split from ksoftirqd into their own kthread
+(timersd) that isn't boosted. It has the same SCHED_FIFO low prio as
+rcu_torture_boost() and therefore timers can't preempt it and may
+starve.
+
+The issue can be triggered in practice on v5.17.1-rt17 using:
+
+ ./kvm.sh --allcpus --configs TREE04 --duration 10m --kconfig "CONFIG_EXPERT=y CONFIG_PREEMPT_RT=y"
+
+Fix this with statically boosting timersd just like is done with
+ksoftirqd in commit
+ ea6d962e80b61 ("rcutorture: Judge RCU priority boosting on grace periods, not callbacks")
+
+Suggested-by: Mel Gorman <mgorman@suse.de>
+Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
+Link: https://lkml.kernel.org/r/20220405010752.1347437-1-frederic@kernel.org
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ include/linux/interrupt.h | 1 +
+ kernel/rcu/rcutorture.c | 6 ++++++
+ kernel/softirq.c | 2 +-
+ 3 files changed, 8 insertions(+), 1 deletion(-)
+
+--- a/include/linux/interrupt.h
++++ b/include/linux/interrupt.h
+@@ -624,6 +624,7 @@ extern void raise_softirq_irqoff(unsigne
+ extern void raise_softirq(unsigned int nr);
+
+ #ifdef CONFIG_PREEMPT_RT
++DECLARE_PER_CPU(struct task_struct *, timersd);
+ extern void raise_timer_softirq(void);
+ extern void raise_hrtimer_softirq(void);
+
+--- a/kernel/rcu/rcutorture.c
++++ b/kernel/rcu/rcutorture.c
+@@ -3294,6 +3294,12 @@ rcu_torture_init(void)
+ WARN_ON_ONCE(!t);
+ sp.sched_priority = 2;
+ sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
++#ifdef CONFIG_PREEMPT_RT
++ t = per_cpu(timersd, cpu);
++ WARN_ON_ONCE(!t);
++ sp.sched_priority = 2;
++ sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
++#endif
+ }
+ }
+ }
+--- a/kernel/softirq.c
++++ b/kernel/softirq.c
+@@ -637,7 +637,7 @@ static inline void tick_irq_exit(void)
+ #endif
+ }
+
+-static DEFINE_PER_CPU(struct task_struct *, timersd);
++DEFINE_PER_CPU(struct task_struct *, timersd);
+ static DEFINE_PER_CPU(unsigned long, pending_timer_softirq);
+
+ static unsigned int local_pending_timers(void)
diff --git a/patches/series b/patches/series
index db6e53b41582..956481f72a27 100644
--- a/patches/series
+++ b/patches/series
@@ -47,6 +47,8 @@ SUNRPC-Don-t-disable-preemption-while-calling-svc_po.patch
0002-scsi-fcoe-Use-per-CPU-API-to-update-per-CPU-statisti.patch
0003-scsi-libfc-Remove-get_cpu-semantics-in-fc_exch_em_al.patch
0004-scsi-bnx2fc-Avoid-using-get_cpu-in-bnx2fc_cmd_alloc.patch
+genirq-irq_sim-Make-the-irq_work-always-run-in-hard-.patch
+genirq-Provide-generic_handle_domain_irq_safe.patch
# Eric's ptrace, v4
0001-signal-Rename-send_signal-send_signal_locked.patch
@@ -90,11 +92,15 @@ x86__Enable_RT_also_on_32bit.patch
# For later, not essencial
###########################################################################
softirq-Use-a-dedicated-thread-for-timer-wakeups.patch
+rcutorture-Also-force-sched-priority-to-timersd-on-b.patch
+tick-Fix-timer-storm-since-introduction-of-timersd.patch
tpm_tis__fix_stall_after_iowrites.patch
drivers_block_zram__Replace_bit_spinlocks_with_rtmutex_for_-rt.patch
generic-softirq-Disable-softirq-stacks-on-PREEMPT_RT.patch
softirq-Disable-softirq-stacks-on-PREEMPT_RT.patch
crypto-cryptd-Protect-per-CPU-resource-by-disabling-.patch
+iio-adc-stm32-adc-Use-generic_handle_domain_irq.patch
+locking-lockdep-Remove-lockdep_init_map_crosslock.patch
###########################################################################
# DRM:
diff --git a/patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch b/patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch
new file mode 100644
index 000000000000..3febe509a913
--- /dev/null
+++ b/patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch
@@ -0,0 +1,105 @@
+From: Frederic Weisbecker <frederic@kernel.org>
+Date: Tue, 5 Apr 2022 03:07:52 +0200
+Subject: [PATCH] tick: Fix timer storm since introduction of timersd
+
+If timers are pending while the tick is reprogrammed on nohz_mode, the
+next expiry is not armed to fire now, it is delayed one jiffy forward
+instead so as not to raise an inextinguishable timer storm with such
+scenario:
+
+1) IRQ triggers and queue a timer
+2) ksoftirqd() is woken up
+3) IRQ tail: timer is reprogrammed to fire now
+4) IRQ exit
+5) TIMER interrupt
+6) goto 3)
+
+...all that until we finally reach ksoftirqd.
+
+Unfortunately we are checking the wrong softirq vector bitmask since
+timersd kthread has split from ksoftirqd. Timers now have their own
+vector state field that must be checked separately. As a result, the
+old timer storm is back. This shows up early on boot with extremely long
+initcalls:
+
+ [ 333.004807] initcall dquot_init+0x0/0x111 returned 0 after 323822879 usecs
+
+and the cause is uncovered with the right trace events showing just
+10 microseconds between ticks (~100 000 Hz):
+
+|swapper/-1 1dn.h111 60818582us : hrtimer_expire_entry: hrtimer=00000000e0ef0f6b function=tick_sched_timer now=60415486608
+|swapper/-1 1dn.h111 60818592us : hrtimer_expire_entry: hrtimer=00000000e0ef0f6b function=tick_sched_timer now=60415496082
+|swapper/-1 1dn.h111 60818601us : hrtimer_expire_entry: hrtimer=00000000e0ef0f6b function=tick_sched_timer now=60415505550
+
+Fix this by checking the right timer vector state from the nohz code.
+
+Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
+Cc: Mel Gorman <mgorman@suse.de>
+Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lkml.kernel.org/r/20220405010752.1347437-2-frederic@kernel.org
+---
+ include/linux/interrupt.h | 12 ++++++++++++
+ kernel/softirq.c | 7 +------
+ kernel/time/tick-sched.c | 2 +-
+ 3 files changed, 14 insertions(+), 7 deletions(-)
+
+--- a/include/linux/interrupt.h
++++ b/include/linux/interrupt.h
+@@ -625,9 +625,16 @@ extern void raise_softirq(unsigned int n
+
+ #ifdef CONFIG_PREEMPT_RT
+ DECLARE_PER_CPU(struct task_struct *, timersd);
++DECLARE_PER_CPU(unsigned long, pending_timer_softirq);
++
+ extern void raise_timer_softirq(void);
+ extern void raise_hrtimer_softirq(void);
+
++static inline unsigned int local_pending_timers(void)
++{
++ return __this_cpu_read(pending_timer_softirq);
++}
++
+ #else
+ static inline void raise_timer_softirq(void)
+ {
+@@ -638,6 +645,11 @@ static inline void raise_hrtimer_softirq
+ {
+ raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+ }
++
++static inline unsigned int local_pending_timers(void)
++{
++ return local_softirq_pending();
++}
+ #endif
+
+ DECLARE_PER_CPU(struct task_struct *, ksoftirqd);
+--- a/kernel/softirq.c
++++ b/kernel/softirq.c
+@@ -638,12 +638,7 @@ static inline void tick_irq_exit(void)
+ }
+
+ DEFINE_PER_CPU(struct task_struct *, timersd);
+-static DEFINE_PER_CPU(unsigned long, pending_timer_softirq);
+-
+-static unsigned int local_pending_timers(void)
+-{
+- return __this_cpu_read(pending_timer_softirq);
+-}
++DEFINE_PER_CPU(unsigned long, pending_timer_softirq);
+
+ static void wake_timersd(void)
+ {
+--- a/kernel/time/tick-sched.c
++++ b/kernel/time/tick-sched.c
+@@ -780,7 +780,7 @@ static void tick_nohz_restart(struct tic
+
+ static inline bool local_timer_softirq_pending(void)
+ {
+- return local_softirq_pending() & BIT(TIMER_SOFTIRQ);
++ return local_pending_timers() & BIT(TIMER_SOFTIRQ);
+ }
+
+ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)