irq_work.c 4.9 KB
Newer Older
1 2 3 4 5 6 7
/*
 * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
 *
 * Provides a framework for enqueueing and running callbacks from hardirq
 * context. The enqueueing is NMI-safe.
 */

8
#include <linux/bug.h>
9
#include <linux/kernel.h>
10
#include <linux/export.h>
11
#include <linux/irq_work.h>
12
#include <linux/percpu.h>
13
#include <linux/hardirq.h>
14
#include <linux/irqflags.h>
15 16
#include <linux/sched.h>
#include <linux/tick.h>
S
Steven Rostedt 已提交
17 18
#include <linux/cpu.h>
#include <linux/notifier.h>
19
#include <linux/smp.h>
20
#include <asm/processor.h>
21 22


23 24
static DEFINE_PER_CPU(struct llist_head, raised_list);
static DEFINE_PER_CPU(struct llist_head, lazy_list);
25 26 27 28

/*
 * Claim the entry so that no one else will poke at it.
 */
29
static bool irq_work_claim(struct irq_work *work)
30
{
31
	unsigned long flags, oflags, nflags;
32

33 34 35 36 37
	/*
	 * Start with our best wish as a premise but only trust any
	 * flag value after cmpxchg() result.
	 */
	flags = work->flags & ~IRQ_WORK_PENDING;
38 39
	for (;;) {
		nflags = flags | IRQ_WORK_FLAGS;
40 41
		oflags = cmpxchg(&work->flags, flags, nflags);
		if (oflags == flags)
42
			break;
43 44 45
		if (oflags & IRQ_WORK_PENDING)
			return false;
		flags = oflags;
46 47
		cpu_relax();
	}
48 49 50 51 52 53 54 55 56 57 58

	return true;
}

void __weak arch_irq_work_raise(void)
{
	/*
	 * Lame architectures will get the timer tick callback
	 */
}

59
#ifdef CONFIG_SMP
60
/*
61
 * Enqueue the irq_work @work on @cpu unless it's already pending
62 63 64
 * somewhere.
 *
 * Can be re-enqueued while the callback is still in progress.
65
 */
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
bool irq_work_queue_on(struct irq_work *work, int cpu)
{
	/* All work should have been flushed before going offline */
	WARN_ON_ONCE(cpu_is_offline(cpu));

	/* Arch remote IPI send/receive backend aren't NMI safe */
	WARN_ON_ONCE(in_nmi());

	/* Only queue if not already pending */
	if (!irq_work_claim(work))
		return false;

	if (llist_add(&work->llnode, &per_cpu(raised_list, cpu)))
		arch_send_call_function_single_ipi(cpu);

	return true;
}
EXPORT_SYMBOL_GPL(irq_work_queue_on);
#endif

/* Enqueue the irq work @work on the current CPU */
87
bool irq_work_queue(struct irq_work *work)
88
{
89 90
	/* Only queue if not already pending */
	if (!irq_work_claim(work))
91
		return false;
92 93

	/* Queue the entry and raise the IPI if needed. */
94
	preempt_disable();
95

96 97 98 99 100 101 102
	/* If the work is "lazy", handle it from next tick if any */
	if (work->flags & IRQ_WORK_LAZY) {
		if (llist_add(&work->llnode, &__get_cpu_var(lazy_list)) &&
		    tick_nohz_tick_stopped())
			arch_irq_work_raise();
	} else {
		if (llist_add(&work->llnode, &__get_cpu_var(raised_list)))
103 104
			arch_irq_work_raise();
	}
105

106
	preempt_enable();
107 108

	return true;
109 110 111
}
EXPORT_SYMBOL_GPL(irq_work_queue);

112 113
bool irq_work_needs_cpu(void)
{
114
	struct llist_head *raised, *lazy;
115

116 117 118
	raised = &__get_cpu_var(raised_list);
	lazy = &__get_cpu_var(lazy_list);
	if (llist_empty(raised) && llist_empty(lazy))
119 120
		return false;

121 122 123
	/* All work should have been flushed before going offline */
	WARN_ON_ONCE(cpu_is_offline(smp_processor_id()));

124 125 126
	return true;
}

127
static void irq_work_run_list(struct llist_head *list)
128
{
129
	unsigned long flags;
130 131
	struct irq_work *work;
	struct llist_node *llnode;
132

133
	BUG_ON(!irqs_disabled());
134

135
	if (llist_empty(list))
136 137
		return;

138
	llnode = llist_del_all(list);
139 140
	while (llnode != NULL) {
		work = llist_entry(llnode, struct irq_work, llnode);
141

P
Peter Zijlstra 已提交
142
		llnode = llist_next(llnode);
143 144

		/*
145
		 * Clear the PENDING bit, after this point the @work
146
		 * can be re-used.
147 148 149
		 * Make it immediately visible so that other CPUs trying
		 * to claim that work don't rely on us to handle their data
		 * while we are in the middle of the func.
150
		 */
151 152 153
		flags = work->flags & ~IRQ_WORK_PENDING;
		xchg(&work->flags, flags);

154
		work->func(work);
155 156 157 158
		/*
		 * Clear the BUSY bit and return to the free state if
		 * no-one else claimed it meanwhile.
		 */
159
		(void)cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY);
160 161
	}
}
S
Steven Rostedt 已提交
162

163 164 165 166 167 168
static void __irq_work_run(void)
{
	irq_work_run_list(&__get_cpu_var(raised_list));
	irq_work_run_list(&__get_cpu_var(lazy_list));
}

S
Steven Rostedt 已提交
169 170 171 172 173 174 175 176 177
/*
 * Run the irq_work entries on this cpu. Requires to be ran from hardirq
 * context with local IRQs disabled.
 */
void irq_work_run(void)
{
	BUG_ON(!in_irq());
	__irq_work_run();
}
178 179 180 181 182 183
EXPORT_SYMBOL_GPL(irq_work_run);

/*
 * Synchronize against the irq_work @entry, ensures the entry is not
 * currently in use.
 */
184
void irq_work_sync(struct irq_work *work)
185 186 187
{
	WARN_ON_ONCE(irqs_disabled());

188
	while (work->flags & IRQ_WORK_BUSY)
189 190 191
		cpu_relax();
}
EXPORT_SYMBOL_GPL(irq_work_sync);
S
Steven Rostedt 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

#ifdef CONFIG_HOTPLUG_CPU
static int irq_work_cpu_notify(struct notifier_block *self,
			       unsigned long action, void *hcpu)
{
	long cpu = (long)hcpu;

	switch (action) {
	case CPU_DYING:
		/* Called from stop_machine */
		if (WARN_ON_ONCE(cpu != smp_processor_id()))
			break;
		__irq_work_run();
		break;
	default:
		break;
	}
	return NOTIFY_OK;
}

static struct notifier_block cpu_notify;

static __init int irq_work_init_cpu_notifier(void)
{
	cpu_notify.notifier_call = irq_work_cpu_notify;
	cpu_notify.priority = 0;
	register_cpu_notifier(&cpu_notify);
	return 0;
}
device_initcall(irq_work_init_cpu_notifier);

#endif /* CONFIG_HOTPLUG_CPU */