2 * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
4 * Provides a framework for enqueueing and running callbacks from hardirq
5 * context. The enqueueing is NMI-safe.
8 #include <linux/kernel.h>
9 #include <linux/export.h>
10 #include <linux/irq_work.h>
11 #include <linux/percpu.h>
12 #include <linux/hardirq.h>
13 #include <asm/processor.h>
16 * An entry can be in one of four states:
18 * free NULL, 0 -> {claimed} : free to be used
19 * claimed NULL, 3 -> {pending} : claimed to be enqueued
20 * pending next, 3 -> {busy} : queued, pending callback
21 * busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed
23 * We use the lower two bits of the next pointer to keep PENDING and BUSY
27 #define IRQ_WORK_PENDING 1UL
28 #define IRQ_WORK_BUSY 2UL
29 #define IRQ_WORK_FLAGS 3UL
31 static inline bool irq_work_is_set(struct irq_work
*entry
, int flags
)
33 return (unsigned long)entry
->next
& flags
;
36 static inline struct irq_work
*irq_work_next(struct irq_work
*entry
)
38 unsigned long next
= (unsigned long)entry
->next
;
39 next
&= ~IRQ_WORK_FLAGS
;
40 return (struct irq_work
*)next
;
43 static inline struct irq_work
*next_flags(struct irq_work
*entry
, int flags
)
45 unsigned long next
= (unsigned long)entry
;
47 return (struct irq_work
*)next
;
50 static DEFINE_PER_CPU(struct irq_work
*, irq_work_list
);
53 * Claim the entry so that no one else will poke at it.
55 static bool irq_work_claim(struct irq_work
*entry
)
57 struct irq_work
*next
, *nflags
;
61 if ((unsigned long)next
& IRQ_WORK_PENDING
)
63 nflags
= next_flags(next
, IRQ_WORK_FLAGS
);
64 } while (cmpxchg(&entry
->next
, next
, nflags
) != next
);
70 void __weak
arch_irq_work_raise(void)
73 * Lame architectures will get the timer tick callback
78 * Queue the entry and raise the IPI if needed.
80 static void __irq_work_queue(struct irq_work
*entry
)
82 struct irq_work
*next
;
87 next
= __this_cpu_read(irq_work_list
);
88 /* Can assign non-atomic because we keep the flags set. */
89 entry
->next
= next_flags(next
, IRQ_WORK_FLAGS
);
90 } while (this_cpu_cmpxchg(irq_work_list
, next
, entry
) != next
);
92 /* The list was empty, raise self-interrupt to start processing. */
93 if (!irq_work_next(entry
))
94 arch_irq_work_raise();
100 * Enqueue the irq_work @entry, returns true on success, failure when the
101 * @entry was already enqueued by someone else.
103 * Can be re-enqueued while the callback is still in progress.
105 bool irq_work_queue(struct irq_work
*entry
)
107 if (!irq_work_claim(entry
)) {
109 * Already enqueued, can't do!
114 __irq_work_queue(entry
);
117 EXPORT_SYMBOL_GPL(irq_work_queue
);
120 * Run the irq_work entries on this cpu. Requires to be ran from hardirq
121 * context with local IRQs disabled.
123 void irq_work_run(void)
125 struct irq_work
*list
;
127 if (this_cpu_read(irq_work_list
) == NULL
)
131 BUG_ON(!irqs_disabled());
133 list
= this_cpu_xchg(irq_work_list
, NULL
);
135 while (list
!= NULL
) {
136 struct irq_work
*entry
= list
;
138 list
= irq_work_next(list
);
141 * Clear the PENDING bit, after this point the @entry
144 entry
->next
= next_flags(NULL
, IRQ_WORK_BUSY
);
147 * Clear the BUSY bit and return to the free state if
148 * no-one else claimed it meanwhile.
150 (void)cmpxchg(&entry
->next
,
151 next_flags(NULL
, IRQ_WORK_BUSY
),
155 EXPORT_SYMBOL_GPL(irq_work_run
);
158 * Synchronize against the irq_work @entry, ensures the entry is not
161 void irq_work_sync(struct irq_work
*entry
)
163 WARN_ON_ONCE(irqs_disabled());
165 while (irq_work_is_set(entry
, IRQ_WORK_BUSY
))
168 EXPORT_SYMBOL_GPL(irq_work_sync
);