linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe
@ 2021-03-09  8:42 Thomas Gleixner
  2021-03-09  8:42 ` [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait() Thomas Gleixner
                   ` (14 more replies)
  0 siblings, 15 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

This is a follow up to the review comments of the series which makes
softirq processing PREEMPT_RT safe:

 https://lore.kernel.org/r/20201207114743.GK3040@hirez.programming.kicks-ass.net

Peter suggested to replace the spin waiting in tasklet_disable() and
tasklet_kill() with wait_event(). This also gets rid of the ill defined
sched_yield() in tasklet_kill().

Analyzing all usage sites of tasklet_disable() and tasklet_unlock_wait() we
found that most of them are safe to be converted to a sleeping wait.

Only a few instances invoke tasklet_disable() from atomic context. A few
bugs which have been found in course of this analysis have been already
addressed seperately.

The following series takes the following approach:

    1) Provide a variant of tasklet_disable() which can be invoked from
       atomic contexts

    2) Convert the usage sites which cannot be easily changed to a
       sleepable wait to use this new function

    3) Replace the spin waits in tasklet_disable() and tasklet_kill() with
       sleepable variants.

If this is agreed on then the merging can be either done in bulk or the
first 4 patches could be applied on top of rc2 and tagged for consumption
in the relevant subsystem trees (networking, pci, firewire). In this case
the last patch which changes the implementation of tasklet_disable() has to
be post-poned until all other changes have reached mainline.

The series is also available from git:

  git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git tasklet-2021-03-09

Thanks,

	tglx



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 02/14] tasklets: Use static inlines for stub implementations Thomas Gleixner
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

A barrier() in a tight loop which waits for something to happen on a remote
CPU is a pointless exercise. Replace it with cpu_relax() which allows HT
siblings to make progress.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 include/linux/interrupt.h |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -672,7 +672,8 @@ static inline void tasklet_unlock(struct
 
 static inline void tasklet_unlock_wait(struct tasklet_struct *t)
 {
-	while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
+	while (test_bit(TASKLET_STATE_RUN, &t->state))
+		cpu_relax();
 }
 #else
 #define tasklet_trylock(t) 1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 02/14] tasklets: Use static inlines for stub implementations
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
  2021-03-09  8:42 ` [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 03/14] tasklets: Provide tasklet_disable_in_atomic() Thomas Gleixner
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

Inlines exist for a reason.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 include/linux/interrupt.h |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -676,9 +676,9 @@ static inline void tasklet_unlock_wait(s
 		cpu_relax();
 }
 #else
-#define tasklet_trylock(t) 1
-#define tasklet_unlock_wait(t) do { } while (0)
-#define tasklet_unlock(t) do { } while (0)
+static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; }
+static inline void tasklet_unlock(struct tasklet_struct *t) { }
+static inline void tasklet_unlock_wait(struct tasklet_struct *t) { }
 #endif
 
 extern void __tasklet_schedule(struct tasklet_struct *t);


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 03/14] tasklets: Provide tasklet_disable_in_atomic()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
  2021-03-09  8:42 ` [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait() Thomas Gleixner
  2021-03-09  8:42 ` [patch 02/14] tasklets: Use static inlines for stub implementations Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 04/14] tasklets: Use spin wait in tasklet_disable() temporarily Thomas Gleixner
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

Replacing the spin wait loops in tasklet_unlock_wait() with
wait_var_event() is not possible as a handful of tasklet_disable()
invocations are happening in atomic context. All other invocations are in
teardown paths which can sleep.

Provide tasklet_disable_in_atomic() and tasklet_unlock_spin_wait() to
convert the few atomic use cases over, which allows to change
tasklet_disable() and tasklet_unlock_wait() in a later step.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/interrupt.h |   22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -675,10 +675,21 @@ static inline void tasklet_unlock_wait(s
 	while (test_bit(TASKLET_STATE_RUN, &t->state))
 		cpu_relax();
 }
+
+/*
+ * Do not use in new code. Waiting for tasklets from atomic contexts is
+ * error prone and should be avoided.
+ */
+static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
+{
+	while (test_bit(TASKLET_STATE_RUN, &t->state))
+		cpu_relax();
+}
 #else
 static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; }
 static inline void tasklet_unlock(struct tasklet_struct *t) { }
 static inline void tasklet_unlock_wait(struct tasklet_struct *t) { }
+static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t) { }
 #endif
 
 extern void __tasklet_schedule(struct tasklet_struct *t);
@@ -703,6 +714,17 @@ static inline void tasklet_disable_nosyn
 	smp_mb__after_atomic();
 }
 
+/*
+ * Do not use in new code. Disabling tasklets from atomic contexts is
+ * error prone and should be avoided.
+ */
+static inline void tasklet_disable_in_atomic(struct tasklet_struct *t)
+{
+	tasklet_disable_nosync(t);
+	tasklet_unlock_spin_wait(t);
+	smp_mb();
+}
+
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 04/14] tasklets: Use spin wait in tasklet_disable() temporarily
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (2 preceding siblings ...)
  2021-03-09  8:42 ` [patch 03/14] tasklets: Provide tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 05/14] tasklets: Replace spin wait in tasklet_unlock_wait() Thomas Gleixner
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

To ease the transition use spin waiting in tasklet_disable() until all
usage sites from atomic context have been cleaned up.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/interrupt.h |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -728,7 +728,8 @@ static inline void tasklet_disable_in_at
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);
-	tasklet_unlock_wait(t);
+	/* Spin wait until all atomic users are converted */
+	tasklet_unlock_spin_wait(t);
 	smp_mb();
 }
 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 05/14] tasklets: Replace spin wait in tasklet_unlock_wait()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (3 preceding siblings ...)
  2021-03-09  8:42 ` [patch 04/14] tasklets: Use spin wait in tasklet_disable() temporarily Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 06/14] tasklets: Replace spin wait in tasklet_kill() Thomas Gleixner
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

From: Peter Zijlstra <peterz@infradead.org>

tasklet_unlock_wait() spin waits for TASKLET_STATE_RUN to be cleared. This
is wasting CPU cycles in a tight loop which is especially painful in a
guest when the CPU running the tasklet is scheduled out.

tasklet_unlock_wait() is invoked from tasklet_kill() which is used in
teardown paths and not performance critical at all. Replace the spin wait
with wait_var_event().

There are no users of tasklet_unlock_wait() which are invoked from atomic
contexts. The usage in tasklet_disable() has been replaced temporarily with
the spin waiting variant until the atomic users are fixed up and will be
converted to the sleep wait variant later.

Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/interrupt.h |   13 ++-----------
 kernel/softirq.c          |   18 ++++++++++++++++++
 2 files changed, 20 insertions(+), 11 deletions(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -664,17 +664,8 @@ static inline int tasklet_trylock(struct
 	return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
 }
 
-static inline void tasklet_unlock(struct tasklet_struct *t)
-{
-	smp_mb__before_atomic();
-	clear_bit(TASKLET_STATE_RUN, &(t)->state);
-}
-
-static inline void tasklet_unlock_wait(struct tasklet_struct *t)
-{
-	while (test_bit(TASKLET_STATE_RUN, &t->state))
-		cpu_relax();
-}
+void tasklet_unlock(struct tasklet_struct *t);
+void tasklet_unlock_wait(struct tasklet_struct *t);
 
 /*
  * Do not use in new code. Waiting for tasklets from atomic contexts is
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -25,6 +25,7 @@
 #include <linux/smpboot.h>
 #include <linux/tick.h>
 #include <linux/irq.h>
+#include <linux/wait_bit.h>
 
 #include <asm/softirq_stack.h>
 
@@ -621,6 +622,23 @@ void tasklet_kill(struct tasklet_struct
 }
 EXPORT_SYMBOL(tasklet_kill);
 
+#ifdef CONFIG_SMP
+void tasklet_unlock(struct tasklet_struct *t)
+{
+	smp_mb__before_atomic();
+	clear_bit(TASKLET_STATE_RUN, &t->state);
+	smp_mb__after_atomic();
+	wake_up_var(&t->state);
+}
+EXPORT_SYMBOL_GPL(tasklet_unlock);
+
+void tasklet_unlock_wait(struct tasklet_struct *t)
+{
+	wait_var_event(&t->state, !test_bit(TASKLET_STATE_RUN, &t->state));
+}
+EXPORT_SYMBOL_GPL(tasklet_unlock_wait);
+#endif
+
 void __init softirq_init(void)
 {
 	int cpu;


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 06/14] tasklets: Replace spin wait in tasklet_kill()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (4 preceding siblings ...)
  2021-03-09  8:42 ` [patch 05/14] tasklets: Replace spin wait in tasklet_unlock_wait() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT Thomas Gleixner
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

From: Peter Zijlstra <peterz@infradead.org>

tasklet_kill() spin waits for TASKLET_STATE_SCHED to be cleared invoking
yield() from inside the loop. yield() is an ill defined mechanism and the
result might still be wasting CPU cycles in a tight loop which is
especially painful in a guest when the CPU running the tasklet is scheduled
out.

tasklet_kill() is used in teardown paths and not performance critical at
all. Replace the spin wait with wait_var_event().

Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/softirq.c |   23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -532,6 +532,16 @@ void __tasklet_hi_schedule(struct taskle
 }
 EXPORT_SYMBOL(__tasklet_hi_schedule);
 
+static inline bool tasklet_clear_sched(struct tasklet_struct *t)
+{
+	if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) {
+		wake_up_var(&t->state);
+		return true;
+	}
+
+	return false;
+}
+
 static void tasklet_action_common(struct softirq_action *a,
 				  struct tasklet_head *tl_head,
 				  unsigned int softirq_nr)
@@ -551,8 +561,7 @@ static void tasklet_action_common(struct
 
 		if (tasklet_trylock(t)) {
 			if (!atomic_read(&t->count)) {
-				if (!test_and_clear_bit(TASKLET_STATE_SCHED,
-							&t->state))
+				if (!tasklet_clear_sched(t))
 					BUG();
 				if (t->use_callback)
 					t->callback(t);
@@ -612,13 +621,11 @@ void tasklet_kill(struct tasklet_struct
 	if (in_interrupt())
 		pr_notice("Attempt to kill tasklet from interrupt\n");
 
-	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
-		do {
-			yield();
-		} while (test_bit(TASKLET_STATE_SCHED, &t->state));
-	}
+	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
+		wait_var_event(&t->state, !test_bit(TASKLET_STATE_SCHED, &t->state));
+
 	tasklet_unlock_wait(t);
-	clear_bit(TASKLET_STATE_SCHED, &t->state);
+	tasklet_clear_sched(t);
 }
 EXPORT_SYMBOL(tasklet_kill);
 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (5 preceding siblings ...)
  2021-03-09  8:42 ` [patch 06/14] tasklets: Replace spin wait in tasklet_kill() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09 15:00   ` Sebastian Andrzej Siewior
  2021-03-09  8:42 ` [patch 08/14] net: jme: Replace link-change tasklet with work Thomas Gleixner
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

tasklet_unlock_spin_wait() spin waits for the TASKLET_STATE_SCHED bit in
the tasklet state to be cleared. This works on !RT nicely because the
corresponding execution can only happen on a different CPU.

On RT softirq processing is preemptible, therefore a task preempting the
softirq processing thread can spin forever.

Prevent this by invoking local_bh_disable()/enable() inside the loop. In
case that the softirq processing thread was preempted by the current task,
current will block on the local lock which yields the CPU to the preempted
softirq processing thread. If the tasklet is processed on a different CPU
then the local_bh_disable()/enable() pair is just a waste of processor
cycles.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 include/linux/interrupt.h |    2 +-
 kernel/softirq.c          |   28 +++++++++++++++++++++++++++-
 2 files changed, 28 insertions(+), 2 deletions(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -658,7 +658,7 @@ enum
 	TASKLET_STATE_RUN	/* Tasklet is running (SMP only) */
 };
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
 static inline int tasklet_trylock(struct tasklet_struct *t)
 {
 	return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -616,6 +616,32 @@ void tasklet_init(struct tasklet_struct
 }
 EXPORT_SYMBOL(tasklet_init);
 
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
+/*
+ * Do not use in new code. There is no real reason to invoke this from
+ * atomic contexts.
+ */
+void tasklet_unlock_spin_wait(struct tasklet_struct *t)
+{
+	while (test_bit(TASKLET_STATE_RUN, &(t)->state)) {
+		if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
+			/*
+			 * Prevent a live lock when current preempted soft
+			 * interrupt processing or prevents ksoftirqd from
+			 * running. If the tasklet runs on a different CPU
+			 * then this has no effect other than doing the BH
+			 * disable/enable dance for nothing.
+			 */
+			local_bh_disable();
+			local_bh_enable();
+		} else {
+			cpu_relax();
+		}
+	}
+}
+EXPORT_SYMBOL(tasklet_unlock_spin_wait);
+#endif
+
 void tasklet_kill(struct tasklet_struct *t)
 {
 	if (in_interrupt())
@@ -629,7 +655,7 @@ void tasklet_kill(struct tasklet_struct
 }
 EXPORT_SYMBOL(tasklet_kill);
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
 void tasklet_unlock(struct tasklet_struct *t)
 {
 	smp_mb__before_atomic();


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 08/14] net: jme: Replace link-change tasklet with work
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (6 preceding siblings ...)
  2021-03-09  8:42 ` [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 09/14] net: sundance: Use tasklet_disable_in_atomic() Thomas Gleixner
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

The link change tasklet disables the tasklets for tx/rx processing while
upating hw parameters and then enables the tasklets again.

This update can also be pushed into a workqueue where it can be performed
in preemptible context. This allows tasklet_disable() to become sleeping.

Replace the linkch_task tasklet with a work.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 drivers/net/ethernet/jme.c |   10 +++++-----
 drivers/net/ethernet/jme.h |    2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -1265,9 +1265,9 @@ jme_stop_shutdown_timer(struct jme_adapt
 	jwrite32f(jme, JME_APMC, apmc);
 }
 
-static void jme_link_change_tasklet(struct tasklet_struct *t)
+static void jme_link_change_work(struct work_struct *work)
 {
-	struct jme_adapter *jme = from_tasklet(jme, t, linkch_task);
+	struct jme_adapter *jme = container_of(work, struct jme_adapter, linkch_task);
 	struct net_device *netdev = jme->dev;
 	int rc;
 
@@ -1510,7 +1510,7 @@ jme_intr_msi(struct jme_adapter *jme, u3
 		 * all other events are ignored
 		 */
 		jwrite32(jme, JME_IEVE, intrstat);
-		tasklet_schedule(&jme->linkch_task);
+		schedule_work(&jme->linkch_task);
 		goto out_reenable;
 	}
 
@@ -1832,7 +1832,6 @@ jme_open(struct net_device *netdev)
 	jme_clear_pm_disable_wol(jme);
 	JME_NAPI_ENABLE(jme);
 
-	tasklet_setup(&jme->linkch_task, jme_link_change_tasklet);
 	tasklet_setup(&jme->txclean_task, jme_tx_clean_tasklet);
 	tasklet_setup(&jme->rxclean_task, jme_rx_clean_tasklet);
 	tasklet_setup(&jme->rxempty_task, jme_rx_empty_tasklet);
@@ -1920,7 +1919,7 @@ jme_close(struct net_device *netdev)
 
 	JME_NAPI_DISABLE(jme);
 
-	tasklet_kill(&jme->linkch_task);
+	cancel_work_sync(&jme->linkch_task);
 	tasklet_kill(&jme->txclean_task);
 	tasklet_kill(&jme->rxclean_task);
 	tasklet_kill(&jme->rxempty_task);
@@ -3035,6 +3034,7 @@ jme_init_one(struct pci_dev *pdev,
 	atomic_set(&jme->rx_empty, 1);
 
 	tasklet_setup(&jme->pcc_task, jme_pcc_tasklet);
+	INIT_WORK(&jme->linkch_task, jme_link_change_work);
 	jme->dpi.cur = PCC_P1;
 
 	jme->reg_ghc = 0;
--- a/drivers/net/ethernet/jme.h
+++ b/drivers/net/ethernet/jme.h
@@ -411,7 +411,7 @@ struct jme_adapter {
 	struct tasklet_struct	rxempty_task;
 	struct tasklet_struct	rxclean_task;
 	struct tasklet_struct	txclean_task;
-	struct tasklet_struct	linkch_task;
+	struct work_struct	linkch_task;
 	struct tasklet_struct	pcc_task;
 	unsigned long		flags;
 	u32			reg_txcs;


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 09/14] net: sundance: Use tasklet_disable_in_atomic().
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (7 preceding siblings ...)
  2021-03-09  8:42 ` [patch 08/14] net: jme: Replace link-change tasklet with work Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 10/14] ath9k: " Thomas Gleixner
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	Peter Zijlstra, ath9k-devel, Kalle Valo, linux-wireless,
	Chas Williams, linux-atm-general, K. Y. Srinivasan,
	Haiyang Zhang, Stephen Hemminger, Wei Liu, Lorenzo Pieralisi,
	Rob Herring, Bjorn Helgaas, linux-hyperv, linux-pci,
	Stefan Richter, linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

tasklet_disable() is used in the timer callback. This might be distangled,
but without access to the hardware that's a bit risky.

Replace it with tasklet_disable_in_atomic() so tasklet_disable() can be
changed to a sleep wait once all remaining atomic users are converted.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Denis Kirjanov <kda@linux-powerpc.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: netdev@vger.kernel.org
---
 drivers/net/ethernet/dlink/sundance.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/net/ethernet/dlink/sundance.c
+++ b/drivers/net/ethernet/dlink/sundance.c
@@ -963,7 +963,7 @@ static void tx_timeout(struct net_device
 	unsigned long flag;
 
 	netif_stop_queue(dev);
-	tasklet_disable(&np->tx_tasklet);
+	tasklet_disable_in_atomic(&np->tx_tasklet);
 	iowrite16(0, ioaddr + IntrEnable);
 	printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
 		   "TxFrameId %2.2x,"


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 10/14] ath9k: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (8 preceding siblings ...)
  2021-03-09  8:42 ` [patch 09/14] net: sundance: Use tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09 10:23   ` Kalle Valo
  2021-03-09  8:42 ` [patch 11/14] atm: eni: Use tasklet_disable_in_atomic() in the send() callback Thomas Gleixner
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	ath9k-devel, Kalle Valo, David S. Miller, Jakub Kicinski,
	linux-wireless, netdev, Peter Zijlstra, Denis Kirjanov,
	Chas Williams, linux-atm-general, K. Y. Srinivasan,
	Haiyang Zhang, Stephen Hemminger, Wei Liu, Lorenzo Pieralisi,
	Rob Herring, Bjorn Helgaas, linux-hyperv, linux-pci,
	Stefan Richter, linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

All callers of ath9k_beacon_ensure_primary_slot() are preemptible /
acquire a mutex except for this callchain:

  spin_lock_bh(&sc->sc_pcu_lock);
  ath_complete_reset()
  -> ath9k_calculate_summary_state()
     -> ath9k_beacon_ensure_primary_slot()

It's unclear how that can be distangled, so use tasklet_disable_in_atomic()
for now. This allows tasklet_disable() to become sleepable once the
remaining atomic users are cleaned up.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: ath9k-devel@qca.qualcomm.com
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: linux-wireless@vger.kernel.org
Cc: netdev@vger.kernel.org
---
 drivers/net/wireless/ath/ath9k/beacon.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -251,7 +251,7 @@ void ath9k_beacon_ensure_primary_slot(st
 	int first_slot = ATH_BCBUF;
 	int slot;
 
-	tasklet_disable(&sc->bcon_tasklet);
+	tasklet_disable_in_atomic(&sc->bcon_tasklet);
 
 	/* Find first taken slot. */
 	for (slot = 0; slot < ATH_BCBUF; slot++) {


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 11/14] atm: eni: Use tasklet_disable_in_atomic() in the send() callback
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (9 preceding siblings ...)
  2021-03-09  8:42 ` [patch 10/14] ath9k: " Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Chas Williams, linux-atm-general, netdev, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, ath9k-devel,
	Kalle Valo, linux-wireless, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

The atmdev_ops::send callback which calls tasklet_disable() is invoked with
bottom halfs disabled from net_device_ops::ndo_start_xmit(). All other
invocations of tasklet_disable() in this driver happen in preemptible
context.

Change the send() call to use tasklet_disable_in_atomic() which allows
tasklet_disable() to be made sleepable once the remaining atomic context
usage sites are cleaned up.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Chas Williams <3chas3@gmail.com>
Cc: linux-atm-general@lists.sourceforge.net
Cc: netdev@vger.kernel.org
---
 drivers/atm/eni.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -2054,7 +2054,7 @@ static int eni_send(struct atm_vcc *vcc,
 	}
 	submitted++;
 	ATM_SKB(skb)->vcc = vcc;
-	tasklet_disable(&ENI_DEV(vcc->dev)->task);
+	tasklet_disable_in_atomic(&ENI_DEV(vcc->dev)->task);
 	res = do_tx(skb);
 	tasklet_enable(&ENI_DEV(vcc->dev)->task);
 	if (res == enq_ok) return 0;


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (10 preceding siblings ...)
  2021-03-09  8:42 ` [patch 11/14] atm: eni: Use tasklet_disable_in_atomic() in the send() callback Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09 22:17   ` Bjorn Helgaas
  2021-03-10 11:34   ` Wei Liu
  2021-03-09  8:42 ` [patch 13/14] firewire: ohci: Use tasklet_disable_in_atomic() where required Thomas Gleixner
                   ` (2 subsequent siblings)
  14 siblings, 2 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger, Wei Liu,
	Lorenzo Pieralisi, Rob Herring, Bjorn Helgaas, linux-hyperv,
	linux-pci, Peter Zijlstra, Denis Kirjanov, David S. Miller,
	Jakub Kicinski, netdev, ath9k-devel, Kalle Valo, linux-wireless,
	Chas Williams, linux-atm-general, Stefan Richter,
	linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

The hv_compose_msi_msg() callback in irq_chip::irq_compose_msi_msg is
invoked via irq_chip_compose_msi_msg(), which itself is always invoked from
atomic contexts from the guts of the interrupt core code.

There is no way to change this w/o rewriting the whole driver, so use
tasklet_disable_in_atomic() which allows to make tasklet_disable()
sleepable once the remaining atomic users are addressed.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Stephen Hemminger <sthemmin@microsoft.com>
Cc: Wei Liu <wei.liu@kernel.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-hyperv@vger.kernel.org
Cc: linux-pci@vger.kernel.org
---
 drivers/pci/controller/pci-hyperv.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -1458,7 +1458,7 @@ static void hv_compose_msi_msg(struct ir
 	 * Prevents hv_pci_onchannelcallback() from running concurrently
 	 * in the tasklet.
 	 */
-	tasklet_disable(&channel->callback_event);
+	tasklet_disable_in_atomic(&channel->callback_event);
 
 	/*
 	 * Since this function is called with IRQ locks held, can't


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 13/14] firewire: ohci: Use tasklet_disable_in_atomic() where required
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (11 preceding siblings ...)
  2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09  8:42 ` [patch 14/14] tasklets: Switch tasklet_disable() to the sleep wait variant Thomas Gleixner
  2021-03-09 14:04 ` [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Peter Zijlstra
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Stefan Richter, linux1394-devel, Peter Zijlstra, Denis Kirjanov,
	David S. Miller, Jakub Kicinski, netdev, ath9k-devel, Kalle Valo,
	linux-wireless, Chas Williams, linux-atm-general,
	K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger, Wei Liu,
	Lorenzo Pieralisi, Rob Herring, Bjorn Helgaas, linux-hyperv,
	linux-pci

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

tasklet_disable() is invoked in several places. Some of them are in atomic
context which prevents a conversion of tasklet_disable() to a sleepable
function.

The atomic callchains are:

 ar_context_tasklet()
   ohci_cancel_packet()
     tasklet_disable()

 ...
   ohci_flush_iso_completions()
     tasklet_disable()

The invocation of tasklet_disable() from at_context_flush() is always in
preemptible context.

Use tasklet_disable_in_atomic() for the two invocations in
ohci_cancel_packet() and ohci_flush_iso_completions().

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: linux1394-devel@lists.sourceforge.net
---
 drivers/firewire/ohci.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -2545,7 +2545,7 @@ static int ohci_cancel_packet(struct fw_
 	struct driver_data *driver_data = packet->driver_data;
 	int ret = -ENOENT;
 
-	tasklet_disable(&ctx->tasklet);
+	tasklet_disable_in_atomic(&ctx->tasklet);
 
 	if (packet->ack != 0)
 		goto out;
@@ -3465,7 +3465,7 @@ static int ohci_flush_iso_completions(st
 	struct iso_context *ctx = container_of(base, struct iso_context, base);
 	int ret = 0;
 
-	tasklet_disable(&ctx->context.tasklet);
+	tasklet_disable_in_atomic(&ctx->context.tasklet);
 
 	if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) {
 		context_tasklet((unsigned long)&ctx->context);


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [patch 14/14] tasklets: Switch tasklet_disable() to the sleep wait variant
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (12 preceding siblings ...)
  2021-03-09  8:42 ` [patch 13/14] firewire: ohci: Use tasklet_disable_in_atomic() where required Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09 14:04 ` [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Peter Zijlstra
  14 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

 -- NOT FOR IMMEDIATE MERGING --

Now that all users of tasklet_disable() are invoked from sleepable context,
convert it to use tasklet_unlock_wait() which might sleep.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/interrupt.h |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -716,8 +716,7 @@ static inline void tasklet_disable_in_at
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);
-	/* Spin wait until all atomic users are converted */
-	tasklet_unlock_spin_wait(t);
+	tasklet_unlock_wait(t);
 	smp_mb();
 }
 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch 10/14] ath9k: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 ` [patch 10/14] ath9k: " Thomas Gleixner
@ 2021-03-09 10:23   ` Kalle Valo
  0 siblings, 0 replies; 22+ messages in thread
From: Kalle Valo @ 2021-03-09 10:23 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Sebastian Andrzej Siewior,
	Ahmed S. Darwish, ath9k-devel, David S. Miller, Jakub Kicinski,
	linux-wireless, netdev, Peter Zijlstra, Denis Kirjanov,
	Chas Williams, linux-atm-general, K. Y. Srinivasan,
	Haiyang Zhang, Stephen Hemminger, Wei Liu, Lorenzo Pieralisi,
	Rob Herring, Bjorn Helgaas, linux-hyperv, linux-pci,
	Stefan Richter, linux1394-devel

Thomas Gleixner <tglx@linutronix.de> writes:

> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>
> All callers of ath9k_beacon_ensure_primary_slot() are preemptible /
> acquire a mutex except for this callchain:
>
>   spin_lock_bh(&sc->sc_pcu_lock);
>   ath_complete_reset()
>   -> ath9k_calculate_summary_state()
>      -> ath9k_beacon_ensure_primary_slot()
>
> It's unclear how that can be distangled, so use tasklet_disable_in_atomic()
> for now. This allows tasklet_disable() to become sleepable once the
> remaining atomic users are cleaned up.
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Cc: ath9k-devel@qca.qualcomm.com
> Cc: Kalle Valo <kvalo@codeaurora.org>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Jakub Kicinski <kuba@kernel.org>
> Cc: linux-wireless@vger.kernel.org
> Cc: netdev@vger.kernel.org
> ---
>  drivers/net/wireless/ath/ath9k/beacon.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

I assume this goes via some other tree:

Acked-by: Kalle Valo <kvalo@codeaurora.org>

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (13 preceding siblings ...)
  2021-03-09  8:42 ` [patch 14/14] tasklets: Switch tasklet_disable() to the sleep wait variant Thomas Gleixner
@ 2021-03-09 14:04 ` Peter Zijlstra
  14 siblings, 0 replies; 22+ messages in thread
From: Peter Zijlstra @ 2021-03-09 14:04 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Sebastian Andrzej Siewior,
	Ahmed S. Darwish, Denis Kirjanov, David S. Miller,
	Jakub Kicinski, netdev, ath9k-devel, Kalle Valo, linux-wireless,
	Chas Williams, linux-atm-general, K. Y. Srinivasan,
	Haiyang Zhang, Stephen Hemminger, Wei Liu, Lorenzo Pieralisi,
	Rob Herring, Bjorn Helgaas, linux-hyperv, linux-pci,
	Stefan Richter, linux1394-devel

On Tue, Mar 09, 2021 at 09:42:03AM +0100, Thomas Gleixner wrote:
> This is a follow up to the review comments of the series which makes
> softirq processing PREEMPT_RT safe:
> 
>  https://lore.kernel.org/r/20201207114743.GK3040@hirez.programming.kicks-ass.net
> 
> Peter suggested to replace the spin waiting in tasklet_disable() and
> tasklet_kill() with wait_event(). This also gets rid of the ill defined
> sched_yield() in tasklet_kill().
> 
> Analyzing all usage sites of tasklet_disable() and tasklet_unlock_wait() we
> found that most of them are safe to be converted to a sleeping wait.
> 
> Only a few instances invoke tasklet_disable() from atomic context. A few
> bugs which have been found in course of this analysis have been already
> addressed seperately.

Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT
  2021-03-09  8:42 ` [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT Thomas Gleixner
@ 2021-03-09 15:00   ` Sebastian Andrzej Siewior
  2021-03-09 15:21     ` Sebastian Andrzej Siewior
  0 siblings, 1 reply; 22+ messages in thread
From: Sebastian Andrzej Siewior @ 2021-03-09 15:00 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Ahmed S. Darwish, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

On 2021-03-09 09:42:10 [+0100], Thomas Gleixner wrote:
> tasklet_unlock_spin_wait() spin waits for the TASKLET_STATE_SCHED bit in
> the tasklet state to be cleared. This works on !RT nicely because the
…

Could you please fold this:

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 07c7329d21aa7..1c14ccd351091 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -663,15 +663,6 @@ static inline int tasklet_trylock(struct tasklet_struct *t)
 void tasklet_unlock(struct tasklet_struct *t);
 void tasklet_unlock_wait(struct tasklet_struct *t);
 
-/*
- * Do not use in new code. Waiting for tasklets from atomic contexts is
- * error prone and should be avoided.
- */
-static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
-{
-	while (test_bit(TASKLET_STATE_RUN, &t->state))
-		cpu_relax();
-}
 #else
 static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; }
 static inline void tasklet_unlock(struct tasklet_struct *t) { }
diff --git a/kernel/softirq.c b/kernel/softirq.c
index f0074f1344402..c9adc5c462485 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -830,8 +830,8 @@ EXPORT_SYMBOL(tasklet_init);
 
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
 /*
- * Do not use in new code. There is no real reason to invoke this from
- * atomic contexts.
+ * Do not use in new code. Waiting for tasklets from atomic contexts is
+ * error prone and should be avoided.
  */
 void tasklet_unlock_spin_wait(struct tasklet_struct *t)
 {
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT
  2021-03-09 15:00   ` Sebastian Andrzej Siewior
@ 2021-03-09 15:21     ` Sebastian Andrzej Siewior
  2021-03-10  8:35       ` Thomas Gleixner
  0 siblings, 1 reply; 22+ messages in thread
From: Sebastian Andrzej Siewior @ 2021-03-09 15:21 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Ahmed S. Darwish, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

On 2021-03-09 16:00:37 [+0100], To Thomas Gleixner wrote:
> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
> index 07c7329d21aa7..1c14ccd351091 100644
> --- a/include/linux/interrupt.h
> +++ b/include/linux/interrupt.h
> @@ -663,15 +663,6 @@ static inline int tasklet_trylock(struct tasklet_struct *t)
>  void tasklet_unlock(struct tasklet_struct *t);
>  void tasklet_unlock_wait(struct tasklet_struct *t);
>  
> -/*
> - * Do not use in new code. Waiting for tasklets from atomic contexts is
> - * error prone and should be avoided.
> - */
> -static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
> -{
> -	while (test_bit(TASKLET_STATE_RUN, &t->state))
> -		cpu_relax();
> -}

Look at that. The forward declaration for tasklet_unlock_spin_wait()
should have remained. Sorry for that.

Sebastian

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-09 22:17   ` Bjorn Helgaas
  2021-03-10 11:34   ` Wei Liu
  1 sibling, 0 replies; 22+ messages in thread
From: Bjorn Helgaas @ 2021-03-09 22:17 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Sebastian Andrzej Siewior,
	Ahmed S. Darwish, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, Stefan Richter, linux1394-devel

On Tue, Mar 09, 2021 at 09:42:15AM +0100, Thomas Gleixner wrote:
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> 
> The hv_compose_msi_msg() callback in irq_chip::irq_compose_msi_msg is
> invoked via irq_chip_compose_msi_msg(), which itself is always invoked from
> atomic contexts from the guts of the interrupt core code.
> 
> There is no way to change this w/o rewriting the whole driver, so use
> tasklet_disable_in_atomic() which allows to make tasklet_disable()
> sleepable once the remaining atomic users are addressed.
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Cc: "K. Y. Srinivasan" <kys@microsoft.com>
> Cc: Haiyang Zhang <haiyangz@microsoft.com>
> Cc: Stephen Hemminger <sthemmin@microsoft.com>
> Cc: Wei Liu <wei.liu@kernel.org>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Cc: linux-hyperv@vger.kernel.org
> Cc: linux-pci@vger.kernel.org

Acked-by: Bjorn Helgaas <bhelgaas@google.com>

It'd be ideal if you could merge this as a group.  Let me know if you
want me to do anything else.

> ---
>  drivers/pci/controller/pci-hyperv.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> --- a/drivers/pci/controller/pci-hyperv.c
> +++ b/drivers/pci/controller/pci-hyperv.c
> @@ -1458,7 +1458,7 @@ static void hv_compose_msi_msg(struct ir
>  	 * Prevents hv_pci_onchannelcallback() from running concurrently
>  	 * in the tasklet.
>  	 */
> -	tasklet_disable(&channel->callback_event);
> +	tasklet_disable_in_atomic(&channel->callback_event);
>  
>  	/*
>  	 * Since this function is called with IRQ locks held, can't
> 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT
  2021-03-09 15:21     ` Sebastian Andrzej Siewior
@ 2021-03-10  8:35       ` Thomas Gleixner
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Gleixner @ 2021-03-10  8:35 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: LKML, Frederic Weisbecker, Ahmed S. Darwish, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

On Tue, Mar 09 2021 at 16:21, Sebastian Andrzej Siewior wrote:

> On 2021-03-09 16:00:37 [+0100], To Thomas Gleixner wrote:
>> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
>> index 07c7329d21aa7..1c14ccd351091 100644
>> --- a/include/linux/interrupt.h
>> +++ b/include/linux/interrupt.h
>> @@ -663,15 +663,6 @@ static inline int tasklet_trylock(struct tasklet_struct *t)
>>  void tasklet_unlock(struct tasklet_struct *t);
>>  void tasklet_unlock_wait(struct tasklet_struct *t);
>>  
>> -/*
>> - * Do not use in new code. Waiting for tasklets from atomic contexts is
>> - * error prone and should be avoided.
>> - */
>> -static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
>> -{
>> -	while (test_bit(TASKLET_STATE_RUN, &t->state))
>> -		cpu_relax();
>> -}
>
> Look at that. The forward declaration for tasklet_unlock_spin_wait()
> should have remained. Sorry for that.

No idea how I managed to mess that up and fail to notice. Brown
paperbags to the rescue.

Thanks,

        tglx

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
  2021-03-09 22:17   ` Bjorn Helgaas
@ 2021-03-10 11:34   ` Wei Liu
  1 sibling, 0 replies; 22+ messages in thread
From: Wei Liu @ 2021-03-10 11:34 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Sebastian Andrzej Siewior,
	Ahmed S. Darwish, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, Stefan Richter, linux1394-devel

On Tue, Mar 09, 2021 at 09:42:15AM +0100, Thomas Gleixner wrote:
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> 
> The hv_compose_msi_msg() callback in irq_chip::irq_compose_msi_msg is
> invoked via irq_chip_compose_msi_msg(), which itself is always invoked from
> atomic contexts from the guts of the interrupt core code.
> 
> There is no way to change this w/o rewriting the whole driver, so use
> tasklet_disable_in_atomic() which allows to make tasklet_disable()
> sleepable once the remaining atomic users are addressed.
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Acked-by: Wei Liu <wei.liu@kernel.org>

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2021-03-10 11:35 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
2021-03-09  8:42 ` [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait() Thomas Gleixner
2021-03-09  8:42 ` [patch 02/14] tasklets: Use static inlines for stub implementations Thomas Gleixner
2021-03-09  8:42 ` [patch 03/14] tasklets: Provide tasklet_disable_in_atomic() Thomas Gleixner
2021-03-09  8:42 ` [patch 04/14] tasklets: Use spin wait in tasklet_disable() temporarily Thomas Gleixner
2021-03-09  8:42 ` [patch 05/14] tasklets: Replace spin wait in tasklet_unlock_wait() Thomas Gleixner
2021-03-09  8:42 ` [patch 06/14] tasklets: Replace spin wait in tasklet_kill() Thomas Gleixner
2021-03-09  8:42 ` [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT Thomas Gleixner
2021-03-09 15:00   ` Sebastian Andrzej Siewior
2021-03-09 15:21     ` Sebastian Andrzej Siewior
2021-03-10  8:35       ` Thomas Gleixner
2021-03-09  8:42 ` [patch 08/14] net: jme: Replace link-change tasklet with work Thomas Gleixner
2021-03-09  8:42 ` [patch 09/14] net: sundance: Use tasklet_disable_in_atomic() Thomas Gleixner
2021-03-09  8:42 ` [patch 10/14] ath9k: " Thomas Gleixner
2021-03-09 10:23   ` Kalle Valo
2021-03-09  8:42 ` [patch 11/14] atm: eni: Use tasklet_disable_in_atomic() in the send() callback Thomas Gleixner
2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
2021-03-09 22:17   ` Bjorn Helgaas
2021-03-10 11:34   ` Wei Liu
2021-03-09  8:42 ` [patch 13/14] firewire: ohci: Use tasklet_disable_in_atomic() where required Thomas Gleixner
2021-03-09  8:42 ` [patch 14/14] tasklets: Switch tasklet_disable() to the sleep wait variant Thomas Gleixner
2021-03-09 14:04 ` [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Peter Zijlstra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).