2012-10-20 16:22:59

by Frederic Weisbecker

[permalink] [raw]
Subject: [RFC PATCH 0/8] printk: Make it usable on nohz CPUs v2

Hi,

So the design is not quite the same here. Instead of using the ad hoc
printk_tick() in periodic mode and irq_work on nohz mode, printk
is now always using irq_work.

In turn, irq_work subsystem is able to let enqueuers choose between IPI
or lazy tick hook to execute works, and that in order to avoid IPI storm
when we have lots of enqueuing of non-urgent works like klogd wakeup
in short period of time so this keeps the old printk_tick behaviour.

It also teaches irq_work to handle nohz mode.

Warning: only compile tested in x86 for now.

Frederic Weisbecker (8):
irq_work: Move irq_work_raise() declaration/default definition to
arch headers
irq_work: Let the arch tell us about self-IPI support
x86: Implement arch_irq_work_has_ipi()
nohz: Add API to check tick state
irq_work: Make self-IPIs optable
irq_work: Handle queuing without IPI support in dyntick idle mode
irq_work: Remove CONFIG_HAVE_IRQ_WORK
printk: Wake up klogd using irq_work

arch/alpha/Kconfig | 1 -
arch/alpha/include/asm/irq_work.h | 9 +++++
arch/alpha/kernel/time.c | 2 +-
arch/arm/Kconfig | 1 -
arch/arm/include/asm/irq_work.h | 1 +
arch/arm64/Kconfig | 1 -
arch/arm64/include/asm/irq_work.h | 1 +
arch/blackfin/Kconfig | 1 -
arch/blackfin/include/asm/irq_work.h | 1 +
arch/frv/Kconfig | 1 -
arch/frv/include/asm/irq_work.h | 1 +
arch/hexagon/Kconfig | 1 -
arch/hexagon/include/asm/irq_work.h | 1 +
arch/mips/Kconfig | 1 -
arch/mips/include/asm/irq_work.h | 1 +
arch/parisc/Kconfig | 1 -
arch/parisc/include/asm/irq_work.h | 1 +
arch/powerpc/Kconfig | 1 -
arch/powerpc/include/asm/irq_work.h | 8 ++++
arch/powerpc/kernel/time.c | 2 +-
arch/s390/Kconfig | 1 -
arch/s390/include/asm/irq_work.h | 1 +
arch/sh/Kconfig | 1 -
arch/sh/include/asm/irq_work.h | 1 +
arch/sparc/Kconfig | 1 -
arch/sparc/include/asm/irq_work.h | 8 ++++
arch/sparc/kernel/pcr.c | 2 +-
arch/x86/Kconfig | 1 -
arch/x86/include/asm/irq_work.h | 15 ++++++++
arch/x86/kernel/cpu/mcheck/mce.c | 2 +-
arch/x86/kernel/irq_work.c | 6 ++--
arch/x86/kvm/pmu.c | 2 +-
drivers/acpi/apei/ghes.c | 2 +-
drivers/staging/iio/trigger/Kconfig | 1 -
drivers/staging/iio/trigger/iio-trig-sysfs.c | 2 +-
include/asm-generic/irq_work.h | 23 ++++++++++++
include/linux/irq_work.h | 9 ++++-
include/linux/printk.h | 3 --
include/linux/tick.h | 17 ++++++++-
init/Kconfig | 5 +--
kernel/events/core.c | 4 +-
kernel/events/ring_buffer.c | 2 +-
kernel/irq_work.c | 48 +++++++++++++++++++------
kernel/printk.c | 14 ++++----
kernel/time/tick-sched.c | 6 ++--
kernel/timer.c | 1 -
46 files changed, 156 insertions(+), 59 deletions(-)
create mode 100644 arch/alpha/include/asm/irq_work.h
create mode 100644 arch/arm/include/asm/irq_work.h
create mode 100644 arch/arm64/include/asm/irq_work.h
create mode 100644 arch/blackfin/include/asm/irq_work.h
create mode 100644 arch/frv/include/asm/irq_work.h
create mode 100644 arch/hexagon/include/asm/irq_work.h
create mode 100644 arch/mips/include/asm/irq_work.h
create mode 100644 arch/parisc/include/asm/irq_work.h
create mode 100644 arch/powerpc/include/asm/irq_work.h
create mode 100644 arch/s390/include/asm/irq_work.h
create mode 100644 arch/sh/include/asm/irq_work.h
create mode 100644 arch/sparc/include/asm/irq_work.h
create mode 100644 arch/x86/include/asm/irq_work.h
create mode 100644 include/asm-generic/irq_work.h

--
1.7.5.4


2012-10-20 16:23:06

by Frederic Weisbecker

[permalink] [raw]
Subject: [RFC PATCH 4/8] nohz: Add API to check tick state

We need some quick way to check if the CPU has stopped
its tick. This will be useful to implement the printk tick
using the irq work subsystem.

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Paul Gortmaker <[email protected]>
---
include/linux/tick.h | 17 ++++++++++++++++-
kernel/time/tick-sched.c | 2 +-
2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/include/linux/tick.h b/include/linux/tick.h
index f37fceb..2307dd3 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -8,6 +8,8 @@

#include <linux/clockchips.h>
#include <linux/irqflags.h>
+#include <linux/percpu.h>
+#include <linux/hrtimer.h>

#ifdef CONFIG_GENERIC_CLOCKEVENTS

@@ -122,13 +124,26 @@ static inline int tick_oneshot_mode_active(void) { return 0; }
#endif /* !CONFIG_GENERIC_CLOCKEVENTS */

# ifdef CONFIG_NO_HZ
+DECLARE_PER_CPU(struct tick_sched, tick_cpu_sched);
+
+static inline int tick_nohz_tick_stopped(void)
+{
+ return __this_cpu_read(tick_cpu_sched.tick_stopped);
+}
+
extern void tick_nohz_idle_enter(void);
extern void tick_nohz_idle_exit(void);
extern void tick_nohz_irq_exit(void);
extern ktime_t tick_nohz_get_sleep_length(void);
extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time);
extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time);
-# else
+
+# else /* !CONFIG_NO_HZ */
+static inline int tick_nohz_tick_stopped(void)
+{
+ return 0;
+}
+
static inline void tick_nohz_idle_enter(void) { }
static inline void tick_nohz_idle_exit(void) { }

diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index f423bdd..ccc1971 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -28,7 +28,7 @@
/*
* Per cpu nohz control structure
*/
-static DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched);
+DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched);

/*
* The time, when the last jiffy update happened. Protected by xtime_lock.
--
1.7.5.4

2012-10-20 16:23:03

by Frederic Weisbecker

[permalink] [raw]
Subject: [RFC PATCH 3/8] x86: Implement arch_irq_work_has_ipi()

Most of the time, x86 can trigger self-IPIs. Tell
irq work subsystem about it.

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Paul Gortmaker <[email protected]>
---
arch/x86/include/asm/irq_work.h | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/irq_work.h b/arch/x86/include/asm/irq_work.h
index dad8266..c7489cd 100644
--- a/arch/x86/include/asm/irq_work.h
+++ b/arch/x86/include/asm/irq_work.h
@@ -2,8 +2,12 @@
#define _ASM_X86_IRQ_WORK_H

#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/cpufeature.h>
+
extern void __arch_irq_work_raise(void);
#define arch_irq_work_raise __arch_irq_work_raise
+
+#define arch_irq_work_has_ipi() (cpu_has_apic)
#endif

#include <asm-generic/irq_work.h>
--
1.7.5.4

2012-10-20 16:23:26

by Frederic Weisbecker

[permalink] [raw]
Subject: [RFC PATCH 8/8] printk: Wake up klogd using irq_work

klogd is woken up asynchronously from the tick in order
to do it safely.

However if printk is called when the tick is stopped, the reader
won't be woken up until the next interrupt, which might not fire
before a while. As a result, the user may miss some message.

To fix this, lets implement the printk tick using irq work.
This subsystem takes care of the timer tick state and can
fix up accordingly.

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Paul Gortmaker <[email protected]>
---
include/linux/printk.h | 3 ---
init/Kconfig | 1 +
kernel/printk.c | 14 +++++++-------
kernel/time/tick-sched.c | 2 +-
kernel/timer.c | 1 -
5 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/include/linux/printk.h b/include/linux/printk.h
index 9afc01e..86c4b62 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -98,9 +98,6 @@ int no_printk(const char *fmt, ...)
extern asmlinkage __printf(1, 2)
void early_printk(const char *fmt, ...);

-extern int printk_needs_cpu(int cpu);
-extern void printk_tick(void);
-
#ifdef CONFIG_PRINTK
asmlinkage __printf(5, 0)
int vprintk_emit(int facility, int level,
diff --git a/init/Kconfig b/init/Kconfig
index 8ba9fc3..9c42e6a 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1184,6 +1184,7 @@ config HOTPLUG
config PRINTK
default y
bool "Enable support for printk" if EXPERT
+ select IRQ_WORK
help
This option enables normal printk support. Removing it
eliminates most of the message strings from the kernel image
diff --git a/kernel/printk.c b/kernel/printk.c
index 66a2ea3..721f760 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -42,6 +42,7 @@
#include <linux/notifier.h>
#include <linux/rculist.h>
#include <linux/poll.h>
+#include <linux/irq_work.h>

#include <asm/uaccess.h>

@@ -1956,7 +1957,7 @@ int is_console_locked(void)
static DEFINE_PER_CPU(int, printk_pending);
static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);

-void printk_tick(void)
+static void wake_up_klogd_work_func(struct irq_work *irq_work)
{
if (__this_cpu_read(printk_pending)) {
int pending = __this_cpu_xchg(printk_pending, 0);
@@ -1969,17 +1970,16 @@ void printk_tick(void)
}
}

-int printk_needs_cpu(int cpu)
-{
- if (cpu_is_offline(cpu))
- printk_tick();
- return __this_cpu_read(printk_pending);
-}
+static struct irq_work wake_up_klogd_work = {
+ .func = wake_up_klogd_work_func
+};

void wake_up_klogd(void)
{
if (waitqueue_active(&log_wait))
this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
+
+ irq_work_queue(&wake_up_klogd_work, false);
}

static void console_cont_flush(char *text, size_t size)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 5f87bb5..04dd027 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -288,7 +288,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
time_delta = timekeeping_max_deferment();
} while (read_seqretry(&xtime_lock, seq));

- if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) || printk_needs_cpu(cpu) ||
+ if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) ||
arch_needs_cpu(cpu) || irq_work_needs_cpu()) {
next_jiffies = last_jiffies + 1;
delta_jiffies = 1;
diff --git a/kernel/timer.c b/kernel/timer.c
index d5de1b2..5d6d0f1 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1349,7 +1349,6 @@ void update_process_times(int user_tick)
account_process_tick(p, user_tick);
run_local_timers();
rcu_check_callbacks(cpu, user_tick);
- printk_tick();
#ifdef CONFIG_IRQ_WORK
if (in_irq())
irq_work_run();
--
1.7.5.4

2012-10-20 16:23:24

by Frederic Weisbecker

[permalink] [raw]
Subject: [RFC PATCH 7/8] irq_work: Remove CONFIG_HAVE_IRQ_WORK

irq work is supposed to work everywhere because of the irq work
hook in the generic timer tick function.

I might be missing something though...

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Paul Gortmaker <[email protected]>
---
arch/alpha/Kconfig | 1 -
arch/arm/Kconfig | 1 -
arch/arm64/Kconfig | 1 -
arch/blackfin/Kconfig | 1 -
arch/frv/Kconfig | 1 -
arch/hexagon/Kconfig | 1 -
arch/mips/Kconfig | 1 -
arch/parisc/Kconfig | 1 -
arch/powerpc/Kconfig | 1 -
arch/s390/Kconfig | 1 -
arch/sh/Kconfig | 1 -
arch/sparc/Kconfig | 1 -
arch/x86/Kconfig | 1 -
drivers/staging/iio/trigger/Kconfig | 1 -
init/Kconfig | 4 ----
15 files changed, 0 insertions(+), 18 deletions(-)

diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 7da9124..ea86275 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -5,7 +5,6 @@ config ALPHA
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_SYSCALL_WRAPPERS
- select HAVE_IRQ_WORK
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
select HAVE_DMA_ATTRS
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 767aae8..44bdbfe 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -30,7 +30,6 @@ config ARM
select HAVE_KERNEL_LZO
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_XZ
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select HAVE_REGS_AND_STACK_ACCESS_API
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7ff68c9..efa0627 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -17,7 +17,6 @@ config ARM64
select HAVE_GENERIC_DMA_COHERENT
select HAVE_GENERIC_HARDIRQS
select HAVE_HW_BREAKPOINT if PERF_EVENTS
- select HAVE_IRQ_WORK
select HAVE_MEMBLOCK
select HAVE_PERF_EVENTS
select HAVE_SPARSE_IRQ
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index ccd9193..9c588f7 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -24,7 +24,6 @@ config BLACKFIN
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_IDE
- select HAVE_IRQ_WORK
select HAVE_KERNEL_GZIP if RAMKERNEL
select HAVE_KERNEL_BZIP2 if RAMKERNEL
select HAVE_KERNEL_LZMA if RAMKERNEL
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 9d26264..17df48f 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -3,7 +3,6 @@ config FRV
default y
select HAVE_IDE
select HAVE_ARCH_TRACEHOOK
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select HAVE_UID16
select HAVE_GENERIC_HARDIRQS
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index b2fdfb7..8a902a7 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -14,7 +14,6 @@ config HEXAGON
# select HAVE_CLK
# select IRQ_PER_CPU
# select GENERIC_PENDING_IRQ if SMP
- select HAVE_IRQ_WORK
select GENERIC_ATOMIC64
select HAVE_PERF_EVENTS
select HAVE_GENERIC_HARDIRQS
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 35453ea..045bf4d 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -4,7 +4,6 @@ config MIPS
select HAVE_GENERIC_DMA_COHERENT
select HAVE_IDE
select HAVE_OPROFILE
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select HAVE_ARCH_KGDB
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index b87438b..abbdb7a 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -9,7 +9,6 @@ config PARISC
select RTC_DRV_GENERIC
select INIT_ALL_POSSIBLE
select BUG
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select GENERIC_ATOMIC64 if !64BIT
select HAVE_GENERIC_HARDIRQS
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index df7edb8..c071bcb 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -118,7 +118,6 @@ config PPC
select HAVE_SYSCALL_WRAPPERS if PPC64
select GENERIC_ATOMIC64 if PPC32
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 99d2d79..d3e251b 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -78,7 +78,6 @@ config S390
select HAVE_KVM if 64BIT
select HAVE_ARCH_TRACEHOOK
select INIT_ALL_POSSIBLE
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select HAVE_DEBUG_KMEMLEAK
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 3b3e27a..8dc67fd 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -11,7 +11,6 @@ config SUPERH
select HAVE_ARCH_TRACEHOOK
select HAVE_DMA_API_DEBUG
select HAVE_DMA_ATTRS
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select HAVE_DEBUG_BUGVERBOSE
select ARCH_HAVE_CUSTOM_GPIO_H
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 91c780c..17b3c9f 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -22,7 +22,6 @@ config SPARC
select ARCH_WANT_OPTIONAL_GPIOLIB
select RTC_CLASS
select RTC_DRV_M48T59
- select HAVE_IRQ_WORK
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
select HAVE_ARCH_JUMP_LABEL
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 42d2c35..bf1821b 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -26,7 +26,6 @@ config X86
select HAVE_OPROFILE
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
- select HAVE_IRQ_WORK
select HAVE_IOREMAP_PROT
select HAVE_KPROBES
select HAVE_MEMBLOCK
diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig
index 7d32075..d44d3ad 100644
--- a/drivers/staging/iio/trigger/Kconfig
+++ b/drivers/staging/iio/trigger/Kconfig
@@ -21,7 +21,6 @@ config IIO_GPIO_TRIGGER
config IIO_SYSFS_TRIGGER
tristate "SYSFS trigger"
depends on SYSFS
- depends on HAVE_IRQ_WORK
select IRQ_WORK
help
Provides support for using SYSFS entry as IIO triggers.
diff --git a/init/Kconfig b/init/Kconfig
index 4c93533..8ba9fc3 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -20,12 +20,8 @@ config CONSTRUCTORS
bool
depends on !UML

-config HAVE_IRQ_WORK
- bool
-
config IRQ_WORK
bool
- depends on HAVE_IRQ_WORK

config BUILDTIME_EXTABLE_SORT
bool
--
1.7.5.4

2012-10-20 16:23:53

by Frederic Weisbecker

[permalink] [raw]
Subject: [RFC PATCH 6/8] irq_work: Handle queuing without IPI support in dyntick idle mode

If we enqueue a work while in dyntick idle mode and the arch doesn't
have self-IPI support, we may not find an opportunity to run the work
before a while.

In this case, exit the idle loop to re-evaluate irq_work_needs_cpu()
and restart the tick.

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Paul Gortmaker <[email protected]>
---
kernel/irq_work.c | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index 19f537b..f3bdcf4 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -71,6 +71,17 @@ static void __irq_work_queue(struct irq_work *work, bool ipi)
*/
if (ipi || !arch_irq_work_has_ipi() || tick_nohz_tick_stopped())
arch_irq_work_raise();
+
+ /*
+ * If we rely on the timer tick or some obscure way to run the work
+ * while the CPU is in dyntick idle mode, we may not have an opportunity
+ * to do so before a while. Let's just exit the idle loop and hope we
+ * haven't yet reached the last need_resched() check before the CPU goes
+ * to low power mode.
+ */
+ if (!arch_irq_work_has_ipi() && tick_nohz_tick_stopped()
+ && is_idle_task(current))
+ set_need_resched();
}
preempt_enable();
}
--
1.7.5.4

2012-10-20 16:24:11

by Frederic Weisbecker

[permalink] [raw]
Subject: [RFC PATCH 5/8] irq_work: Make self-IPIs optable

While queuing an irq work, let the caller choose between
triggering a self-IPI right away, provided the arch is able
to do so, or waiting for the next timer interrupt to run the work.

Some non-urgent enqueuers like printk may prefer not to raise
an IPI storm in case of frequent calls on short periods of
time.

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Paul Gortmaker <[email protected]>
---
arch/x86/kernel/cpu/mcheck/mce.c | 2 +-
arch/x86/kvm/pmu.c | 2 +-
drivers/acpi/apei/ghes.c | 2 +-
drivers/staging/iio/trigger/iio-trig-sysfs.c | 2 +-
include/linux/irq_work.h | 8 +++++-
kernel/events/core.c | 4 +-
kernel/events/ring_buffer.c | 2 +-
kernel/irq_work.c | 32 +++++++++++++++++++++-----
kernel/time/tick-sched.c | 2 +-
9 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 29e87d3..3020e95 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -549,7 +549,7 @@ static void mce_report_event(struct pt_regs *regs)
return;
}

- irq_work_queue(&__get_cpu_var(mce_irq_work));
+ irq_work_queue(&__get_cpu_var(mce_irq_work), true);
}

/*
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index cfc258a..0dfc716 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -128,7 +128,7 @@ static void kvm_perf_overflow_intr(struct perf_event *perf_event,
* NMI context. Do it from irq work instead.
*/
if (!kvm_is_in_guest())
- irq_work_queue(&pmc->vcpu->arch.pmu.irq_work);
+ irq_work_queue(&pmc->vcpu->arch.pmu.irq_work, true);
else
kvm_make_request(KVM_REQ_PMI, pmc->vcpu);
}
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 1599566..44be554 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -874,7 +874,7 @@ next:
ghes_clear_estatus(ghes);
}
#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
- irq_work_queue(&ghes_proc_irq_work);
+ irq_work_queue(&ghes_proc_irq_work, true);
#endif

out:
diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c
index 3bac972..7d6f9a9 100644
--- a/drivers/staging/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c
@@ -105,7 +105,7 @@ static ssize_t iio_sysfs_trigger_poll(struct device *dev,
struct iio_trigger *trig = to_iio_trigger(dev);
struct iio_sysfs_trig *sysfs_trig = trig->private_data;

- irq_work_queue(&sysfs_trig->work);
+ irq_work_queue(&sysfs_trig->work, true);

return count;
}
diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h
index b39ea0b..71a33b7 100644
--- a/include/linux/irq_work.h
+++ b/include/linux/irq_work.h
@@ -17,8 +17,14 @@ void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *))
work->func = func;
}

-bool irq_work_queue(struct irq_work *work);
+bool irq_work_queue(struct irq_work *work, bool ipi);
void irq_work_run(void);
void irq_work_sync(struct irq_work *work);

+#ifdef CONFIG_IRQ_WORK
+bool irq_work_needs_cpu(void);
+#else
+static bool irq_work_needs_cpu(void) { return false; }
+#endif
+
#endif /* _LINUX_IRQ_WORK_H */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index cda3ebd..e7cbbcc 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4900,7 +4900,7 @@ static int __perf_event_overflow(struct perf_event *event,
ret = 1;
event->pending_kill = POLL_HUP;
event->pending_disable = 1;
- irq_work_queue(&event->pending);
+ irq_work_queue(&event->pending, true);
}

if (event->overflow_handler)
@@ -4910,7 +4910,7 @@ static int __perf_event_overflow(struct perf_event *event,

if (event->fasync && event->pending_kill) {
event->pending_wakeup = 1;
- irq_work_queue(&event->pending);
+ irq_work_queue(&event->pending, true);
}

return ret;
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 23cb34f..620df7a 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -39,7 +39,7 @@ static void perf_output_wakeup(struct perf_output_handle *handle)
atomic_set(&handle->rb->poll, POLL_IN);

handle->event->pending_wakeup = 1;
- irq_work_queue(&handle->event->pending);
+ irq_work_queue(&handle->event->pending, true);
}

/*
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index 44a5b19..19f537b 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -12,6 +12,8 @@
#include <linux/percpu.h>
#include <linux/hardirq.h>
#include <linux/irqflags.h>
+#include <linux/tick.h>
+#include <linux/sched.h>
#include <asm/processor.h>

/*
@@ -52,7 +54,7 @@ static bool irq_work_claim(struct irq_work *work)
/*
* Queue the entry and raise the IPI if needed.
*/
-static void __irq_work_queue(struct irq_work *work)
+static void __irq_work_queue(struct irq_work *work, bool ipi)
{
bool empty;

@@ -60,9 +62,16 @@ static void __irq_work_queue(struct irq_work *work)

empty = llist_add(&work->llnode, &__get_cpu_var(irq_work_list));
/* The list was empty, raise self-interrupt to start processing. */
- if (empty)
- arch_irq_work_raise();
-
+ if (empty) {
+ /*
+ * If an IPI is requested, raise it right away. Otherwise wait
+ * for the next tick unless it's stopped. Now if the arch uses
+ * some other obscure way than IPI to raise an irq work, just raise
+ * and don't think further.
+ */
+ if (ipi || !arch_irq_work_has_ipi() || tick_nohz_tick_stopped())
+ arch_irq_work_raise();
+ }
preempt_enable();
}

@@ -72,7 +81,7 @@ static void __irq_work_queue(struct irq_work *work)
*
* Can be re-enqueued while the callback is still in progress.
*/
-bool irq_work_queue(struct irq_work *work)
+bool irq_work_queue(struct irq_work *work, bool ipi)
{
if (!irq_work_claim(work)) {
/*
@@ -81,11 +90,22 @@ bool irq_work_queue(struct irq_work *work)
return false;
}

- __irq_work_queue(work);
+ __irq_work_queue(work, ipi);
return true;
}
EXPORT_SYMBOL_GPL(irq_work_queue);

+bool irq_work_needs_cpu(void)
+{
+ struct llist_head *this_list;
+
+ this_list = &__get_cpu_var(irq_work_list);
+ if (llist_empty(this_list))
+ return false;
+
+ return true;
+}
+
/*
* Run the irq_work entries on this cpu. Requires to be ran from hardirq
* context with local IRQs disabled.
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index ccc1971..5f87bb5 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -289,7 +289,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
} while (read_seqretry(&xtime_lock, seq));

if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) || printk_needs_cpu(cpu) ||
- arch_needs_cpu(cpu)) {
+ arch_needs_cpu(cpu) || irq_work_needs_cpu()) {
next_jiffies = last_jiffies + 1;
delta_jiffies = 1;
} else {
--
1.7.5.4

2012-10-20 16:24:34

by Frederic Weisbecker

[permalink] [raw]
Subject: [RFC PATCH 2/8] irq_work: Let the arch tell us about self-IPI support

This prepares us to make printk working on nohz CPUs
using irq work.

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Paul Gortmaker <[email protected]>
---
arch/alpha/include/asm/irq_work.h | 5 ++++-
arch/alpha/kernel/time.c | 2 +-
arch/powerpc/include/asm/irq_work.h | 4 +++-
arch/powerpc/kernel/time.c | 2 +-
arch/sparc/include/asm/irq_work.h | 4 +++-
arch/sparc/kernel/pcr.c | 2 +-
arch/x86/include/asm/irq_work.h | 9 +++++----
arch/x86/kernel/irq_work.c | 2 +-
include/asm-generic/irq_work.h | 14 ++++++++++++++
9 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/arch/alpha/include/asm/irq_work.h b/arch/alpha/include/asm/irq_work.h
index 814ff3d..3d32132 100644
--- a/arch/alpha/include/asm/irq_work.h
+++ b/arch/alpha/include/asm/irq_work.h
@@ -1,6 +1,9 @@
#ifndef _ALPHA_IRQ_WORK_H
#define _ALPHA_IRQ_WORK_H

-extern void arch_irq_work_raise(void);
+extern void __arch_irq_work_raise(void);
+#define arch_irq_work_raise __arch_irq_work_raise
+
+#include <asm-generic/irq_work.h>

#endif
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index e336694..91c5eec 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -90,7 +90,7 @@ DEFINE_PER_CPU(u8, irq_work_pending);
#define test_irq_work_pending() __get_cpu_var(irq_work_pending)
#define clear_irq_work_pending() __get_cpu_var(irq_work_pending) = 0

-void arch_irq_work_raise(void)
+void __arch_irq_work_raise(void)
{
set_irq_work_pending_flag();
}
diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h
index 8b9927f..8aa36aa 100644
--- a/arch/powerpc/include/asm/irq_work.h
+++ b/arch/powerpc/include/asm/irq_work.h
@@ -1,6 +1,8 @@
#ifndef _ASM_POWERPC_IRQ_WORK_H
#define _ASM_POWERPC_IRQ_WORK_H

-extern void arch_irq_work_raise(void);
+extern void __arch_irq_work_raise(void);
+#define arch_irq_work_raise __arch_irq_work_raise

+#include <asm-generic/irq_work.h>
#endif
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index c9986fd..31565ac 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -466,7 +466,7 @@ DEFINE_PER_CPU(u8, irq_work_pending);

#endif /* 32 vs 64 bit */

-void arch_irq_work_raise(void)
+void __arch_irq_work_raise(void)
{
preempt_disable();
set_irq_work_pending_flag();
diff --git a/arch/sparc/include/asm/irq_work.h b/arch/sparc/include/asm/irq_work.h
index 1d062a6..383772d 100644
--- a/arch/sparc/include/asm/irq_work.h
+++ b/arch/sparc/include/asm/irq_work.h
@@ -1,6 +1,8 @@
#ifndef ___ASM_SPARC_IRQ_H
#define ___ASM_SPARC_IRQ_H

-extern void arch_irq_work_raise(void);
+extern void __arch_irq_work_raise(void);
+#define arch_irq_work_raise __arch_irq_work_raise

+#include <asm-generic/irq_work.h>
#endif
diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c
index 269af58..d1e1ecf 100644
--- a/arch/sparc/kernel/pcr.c
+++ b/arch/sparc/kernel/pcr.c
@@ -43,7 +43,7 @@ void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs)
set_irq_regs(old_regs);
}

-void arch_irq_work_raise(void)
+void __arch_irq_work_raise(void)
{
set_softint(1 << PIL_DEFERRED_PCR_WORK);
}
diff --git a/arch/x86/include/asm/irq_work.h b/arch/x86/include/asm/irq_work.h
index 38eed96..dad8266 100644
--- a/arch/x86/include/asm/irq_work.h
+++ b/arch/x86/include/asm/irq_work.h
@@ -1,10 +1,11 @@
#ifndef _ASM_X86_IRQ_WORK_H
#define _ASM_X86_IRQ_WORK_H

-#ifndef CONFIG_X86_LOCAL_APIC
-#include <asm-generic/irq_work.h>
-# else
-extern void arch_irq_work_raise(void);
+#ifdef CONFIG_X86_LOCAL_APIC
+extern void __arch_irq_work_raise(void);
+#define arch_irq_work_raise __arch_irq_work_raise
#endif

+#include <asm-generic/irq_work.h>
+
#endif
diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c
index 95f5d4e..7389d5e 100644
--- a/arch/x86/kernel/irq_work.c
+++ b/arch/x86/kernel/irq_work.c
@@ -19,7 +19,7 @@ void smp_irq_work_interrupt(struct pt_regs *regs)
}

#ifdef CONFIG_X86_LOCAL_APIC
-void arch_irq_work_raise(void)
+void __arch_irq_work_raise(void)
{
if (!cpu_has_apic)
return;
diff --git a/include/asm-generic/irq_work.h b/include/asm-generic/irq_work.h
index a2d4108..e3e4f02 100644
--- a/include/asm-generic/irq_work.h
+++ b/include/asm-generic/irq_work.h
@@ -4,6 +4,20 @@
/*
* Lame architectures will get the timer tick callback
*/
+#ifndef arch_irq_work_raise
static inline void arch_irq_work_raise(void) { }
+#endif
+
+/*
+ * Unless told otherwise, consider the arch doesn't implement irq work
+ * using self IPIs but through another way like defaulting to the hook
+ * on the sched tick.
+ */
+#ifndef arch_irq_work_has_ipi
+static inline bool arch_irq_work_has_ipi(void)
+{
+ return false;
+}
+#endif

#endif
--
1.7.5.4

2012-10-20 16:24:49

by Frederic Weisbecker

[permalink] [raw]
Subject: [RFC PATCH 1/8] irq_work: Move irq_work_raise() declaration/default definition to arch headers

This optimization doesn't matter much. But this prepares the
arch headers that we need to add a new API in order to detect
when the arch can trigger self IPIs to implement the irq work.

This is necessary later to make printk working in nohz CPUs.

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Paul Gortmaker <[email protected]>
---
arch/alpha/include/asm/irq_work.h | 6 ++++++
arch/arm/include/asm/irq_work.h | 1 +
arch/arm64/include/asm/irq_work.h | 1 +
arch/blackfin/include/asm/irq_work.h | 1 +
arch/frv/include/asm/irq_work.h | 1 +
arch/hexagon/include/asm/irq_work.h | 1 +
arch/mips/include/asm/irq_work.h | 1 +
arch/parisc/include/asm/irq_work.h | 1 +
arch/powerpc/include/asm/irq_work.h | 6 ++++++
arch/s390/include/asm/irq_work.h | 1 +
arch/sh/include/asm/irq_work.h | 1 +
arch/sparc/include/asm/irq_work.h | 6 ++++++
arch/x86/include/asm/irq_work.h | 10 ++++++++++
arch/x86/kernel/irq_work.c | 4 ++--
include/asm-generic/irq_work.h | 9 +++++++++
include/linux/irq_work.h | 1 +
kernel/irq_work.c | 7 -------
17 files changed, 49 insertions(+), 9 deletions(-)
create mode 100644 arch/alpha/include/asm/irq_work.h
create mode 100644 arch/arm/include/asm/irq_work.h
create mode 100644 arch/arm64/include/asm/irq_work.h
create mode 100644 arch/blackfin/include/asm/irq_work.h
create mode 100644 arch/frv/include/asm/irq_work.h
create mode 100644 arch/hexagon/include/asm/irq_work.h
create mode 100644 arch/mips/include/asm/irq_work.h
create mode 100644 arch/parisc/include/asm/irq_work.h
create mode 100644 arch/powerpc/include/asm/irq_work.h
create mode 100644 arch/s390/include/asm/irq_work.h
create mode 100644 arch/sh/include/asm/irq_work.h
create mode 100644 arch/sparc/include/asm/irq_work.h
create mode 100644 arch/x86/include/asm/irq_work.h
create mode 100644 include/asm-generic/irq_work.h

diff --git a/arch/alpha/include/asm/irq_work.h b/arch/alpha/include/asm/irq_work.h
new file mode 100644
index 0000000..814ff3d
--- /dev/null
+++ b/arch/alpha/include/asm/irq_work.h
@@ -0,0 +1,6 @@
+#ifndef _ALPHA_IRQ_WORK_H
+#define _ALPHA_IRQ_WORK_H
+
+extern void arch_irq_work_raise(void);
+
+#endif
diff --git a/arch/arm/include/asm/irq_work.h b/arch/arm/include/asm/irq_work.h
new file mode 100644
index 0000000..f1bffa2
--- /dev/null
+++ b/arch/arm/include/asm/irq_work.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_work.h>
diff --git a/arch/arm64/include/asm/irq_work.h b/arch/arm64/include/asm/irq_work.h
new file mode 100644
index 0000000..f1bffa2
--- /dev/null
+++ b/arch/arm64/include/asm/irq_work.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_work.h>
diff --git a/arch/blackfin/include/asm/irq_work.h b/arch/blackfin/include/asm/irq_work.h
new file mode 100644
index 0000000..f1bffa2
--- /dev/null
+++ b/arch/blackfin/include/asm/irq_work.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_work.h>
diff --git a/arch/frv/include/asm/irq_work.h b/arch/frv/include/asm/irq_work.h
new file mode 100644
index 0000000..f1bffa2
--- /dev/null
+++ b/arch/frv/include/asm/irq_work.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_work.h>
diff --git a/arch/hexagon/include/asm/irq_work.h b/arch/hexagon/include/asm/irq_work.h
new file mode 100644
index 0000000..f1bffa2
--- /dev/null
+++ b/arch/hexagon/include/asm/irq_work.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_work.h>
diff --git a/arch/mips/include/asm/irq_work.h b/arch/mips/include/asm/irq_work.h
new file mode 100644
index 0000000..f1bffa2
--- /dev/null
+++ b/arch/mips/include/asm/irq_work.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_work.h>
diff --git a/arch/parisc/include/asm/irq_work.h b/arch/parisc/include/asm/irq_work.h
new file mode 100644
index 0000000..f1bffa2
--- /dev/null
+++ b/arch/parisc/include/asm/irq_work.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_work.h>
diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h
new file mode 100644
index 0000000..8b9927f
--- /dev/null
+++ b/arch/powerpc/include/asm/irq_work.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_POWERPC_IRQ_WORK_H
+#define _ASM_POWERPC_IRQ_WORK_H
+
+extern void arch_irq_work_raise(void);
+
+#endif
diff --git a/arch/s390/include/asm/irq_work.h b/arch/s390/include/asm/irq_work.h
new file mode 100644
index 0000000..f1bffa2
--- /dev/null
+++ b/arch/s390/include/asm/irq_work.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_work.h>
diff --git a/arch/sh/include/asm/irq_work.h b/arch/sh/include/asm/irq_work.h
new file mode 100644
index 0000000..f1bffa2
--- /dev/null
+++ b/arch/sh/include/asm/irq_work.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_work.h>
diff --git a/arch/sparc/include/asm/irq_work.h b/arch/sparc/include/asm/irq_work.h
new file mode 100644
index 0000000..1d062a6
--- /dev/null
+++ b/arch/sparc/include/asm/irq_work.h
@@ -0,0 +1,6 @@
+#ifndef ___ASM_SPARC_IRQ_H
+#define ___ASM_SPARC_IRQ_H
+
+extern void arch_irq_work_raise(void);
+
+#endif
diff --git a/arch/x86/include/asm/irq_work.h b/arch/x86/include/asm/irq_work.h
new file mode 100644
index 0000000..38eed96
--- /dev/null
+++ b/arch/x86/include/asm/irq_work.h
@@ -0,0 +1,10 @@
+#ifndef _ASM_X86_IRQ_WORK_H
+#define _ASM_X86_IRQ_WORK_H
+
+#ifndef CONFIG_X86_LOCAL_APIC
+#include <asm-generic/irq_work.h>
+# else
+extern void arch_irq_work_raise(void);
+#endif
+
+#endif
diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c
index ca8f703..95f5d4e 100644
--- a/arch/x86/kernel/irq_work.c
+++ b/arch/x86/kernel/irq_work.c
@@ -18,13 +18,13 @@ void smp_irq_work_interrupt(struct pt_regs *regs)
irq_exit();
}

+#ifdef CONFIG_X86_LOCAL_APIC
void arch_irq_work_raise(void)
{
-#ifdef CONFIG_X86_LOCAL_APIC
if (!cpu_has_apic)
return;

apic->send_IPI_self(IRQ_WORK_VECTOR);
apic_wait_icr_idle();
-#endif
}
+#endif
diff --git a/include/asm-generic/irq_work.h b/include/asm-generic/irq_work.h
new file mode 100644
index 0000000..a2d4108
--- /dev/null
+++ b/include/asm-generic/irq_work.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_ATOMIC_H
+#define __ASM_GENERIC_ATOMIC_H
+
+/*
+ * Lame architectures will get the timer tick callback
+ */
+static inline void arch_irq_work_raise(void) { }
+
+#endif
diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h
index 6a9e8f5..b39ea0b 100644
--- a/include/linux/irq_work.h
+++ b/include/linux/irq_work.h
@@ -2,6 +2,7 @@
#define _LINUX_IRQ_WORK_H

#include <linux/llist.h>
+#include <asm/irq_work.h>

struct irq_work {
unsigned long flags;
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index 1588e3b..44a5b19 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -49,13 +49,6 @@ static bool irq_work_claim(struct irq_work *work)
return true;
}

-void __weak arch_irq_work_raise(void)
-{
- /*
- * Lame architectures will get the timer tick callback
- */
-}
-
/*
* Queue the entry and raise the IPI if needed.
*/
--
1.7.5.4

2012-10-20 16:50:17

by Joe Perches

[permalink] [raw]
Subject: Re: [RFC PATCH 8/8] printk: Wake up klogd using irq_work

On Sat, 2012-10-20 at 12:22 -0400, Frederic Weisbecker wrote:
> lets implement the printk tick using irq work.

Hi Frederic.

Can you redo this change please against -next in a few days?

Andrew Morton picked up this series,
https://lkml.org/lkml/2012/10/17/41
but it's not yet in -next.

https://lkml.org/lkml/2012/10/18/600

kernel/printk.c has been moved to kernel/printk/printk.c
and broken up into multiple files.

thanks, Joe

2012-10-20 17:21:09

by Frederic Weisbecker

[permalink] [raw]
Subject: Re: [RFC PATCH 8/8] printk: Wake up klogd using irq_work

2012/10/20 Joe Perches <[email protected]>:
> On Sat, 2012-10-20 at 12:22 -0400, Frederic Weisbecker wrote:
>> lets implement the printk tick using irq work.
>
> Hi Frederic.
>
> Can you redo this change please against -next in a few days?
>
> Andrew Morton picked up this series,
> https://lkml.org/lkml/2012/10/17/41
> but it's not yet in -next.
>
> https://lkml.org/lkml/2012/10/18/600
>
> kernel/printk.c has been moved to kernel/printk/printk.c
> and broken up into multiple files.

Sure, I will rebase to your work on the next version.

Thanks.

2012-10-22 10:42:34

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [RFC PATCH 5/8] irq_work: Make self-IPIs optable

On Sat, 2012-10-20 at 12:22 -0400, Frederic Weisbecker wrote:
> + if (empty) {
> + /*
> + * If an IPI is requested, raise it right away. Otherwise wait
> + * for the next tick unless it's stopped. Now if the arch uses
> + * some other obscure way than IPI to raise an irq work, just raise
> + * and don't think further.
> + */
> + if (ipi || !arch_irq_work_has_ipi() || tick_nohz_tick_stopped())
> + arch_irq_work_raise();
> + }
> preempt_enable();
> }

Doesn't this have a problem where we enqueue the first lazy and then one
with ipi? In that case it appears we won't send the IPI because the
queue wasn't empty.

2012-10-23 12:34:23

by Frederic Weisbecker

[permalink] [raw]
Subject: Re: [RFC PATCH 5/8] irq_work: Make self-IPIs optable

2012/10/22 Peter Zijlstra <[email protected]>:
> On Sat, 2012-10-20 at 12:22 -0400, Frederic Weisbecker wrote:
>> + if (empty) {
>> + /*
>> + * If an IPI is requested, raise it right away. Otherwise wait
>> + * for the next tick unless it's stopped. Now if the arch uses
>> + * some other obscure way than IPI to raise an irq work, just raise
>> + * and don't think further.
>> + */
>> + if (ipi || !arch_irq_work_has_ipi() || tick_nohz_tick_stopped())
>> + arch_irq_work_raise();
>> + }
>> preempt_enable();
>> }
>
> Doesn't this have a problem where we enqueue the first lazy and then one
> with ipi? In that case it appears we won't send the IPI because the
> queue wasn't empty.

Good point! I need to send an ipi in that case. Will fix on the next version.

Thanks.