]> Pileus Git - ~andy/linux/blob - kernel/irq_work.c
Merge branch 'core/irq_work' of git://git.kernel.org/pub/scm/linux/kernel/git/frederi...
[~andy/linux] / kernel / irq_work.c
1 /*
2  * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
3  *
4  * Provides a framework for enqueueing and running callbacks from hardirq
5  * context. The enqueueing is NMI-safe.
6  */
7
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 #include <asm/processor.h>
16
17 /*
18  * An entry can be in one of four states:
19  *
20  * free      NULL, 0 -> {claimed}       : free to be used
21  * claimed   NULL, 3 -> {pending}       : claimed to be enqueued
22  * pending   next, 3 -> {busy}          : queued, pending callback
23  * busy      NULL, 2 -> {free, claimed} : callback in progress, can be claimed
24  */
25
26 #define IRQ_WORK_PENDING        1UL
27 #define IRQ_WORK_BUSY           2UL
28 #define IRQ_WORK_FLAGS          3UL
29
30 static DEFINE_PER_CPU(struct llist_head, irq_work_list);
31
32 /*
33  * Claim the entry so that no one else will poke at it.
34  */
35 static bool irq_work_claim(struct irq_work *work)
36 {
37         unsigned long flags, oflags, nflags;
38
39         /*
40          * Start with our best wish as a premise but only trust any
41          * flag value after cmpxchg() result.
42          */
43         flags = work->flags & ~IRQ_WORK_PENDING;
44         for (;;) {
45                 nflags = flags | IRQ_WORK_FLAGS;
46                 oflags = cmpxchg(&work->flags, flags, nflags);
47                 if (oflags == flags)
48                         break;
49                 if (oflags & IRQ_WORK_PENDING)
50                         return false;
51                 flags = oflags;
52                 cpu_relax();
53         }
54
55         return true;
56 }
57
58 void __weak arch_irq_work_raise(void)
59 {
60         /*
61          * Lame architectures will get the timer tick callback
62          */
63 }
64
65 /*
66  * Queue the entry and raise the IPI if needed.
67  */
68 static void __irq_work_queue(struct irq_work *work)
69 {
70         bool empty;
71
72         preempt_disable();
73
74         empty = llist_add(&work->llnode, &__get_cpu_var(irq_work_list));
75         /* The list was empty, raise self-interrupt to start processing. */
76         if (empty)
77                 arch_irq_work_raise();
78
79         preempt_enable();
80 }
81
82 /*
83  * Enqueue the irq_work @entry, returns true on success, failure when the
84  * @entry was already enqueued by someone else.
85  *
86  * Can be re-enqueued while the callback is still in progress.
87  */
88 bool irq_work_queue(struct irq_work *work)
89 {
90         if (!irq_work_claim(work)) {
91                 /*
92                  * Already enqueued, can't do!
93                  */
94                 return false;
95         }
96
97         __irq_work_queue(work);
98         return true;
99 }
100 EXPORT_SYMBOL_GPL(irq_work_queue);
101
102 /*
103  * Run the irq_work entries on this cpu. Requires to be ran from hardirq
104  * context with local IRQs disabled.
105  */
106 void irq_work_run(void)
107 {
108         struct irq_work *work;
109         struct llist_head *this_list;
110         struct llist_node *llnode;
111
112         this_list = &__get_cpu_var(irq_work_list);
113         if (llist_empty(this_list))
114                 return;
115
116         BUG_ON(!in_irq());
117         BUG_ON(!irqs_disabled());
118
119         llnode = llist_del_all(this_list);
120         while (llnode != NULL) {
121                 work = llist_entry(llnode, struct irq_work, llnode);
122
123                 llnode = llist_next(llnode);
124
125                 /*
126                  * Clear the PENDING bit, after this point the @work
127                  * can be re-used.
128                  * Make it immediately visible so that other CPUs trying
129                  * to claim that work don't rely on us to handle their data
130                  * while we are in the middle of the func.
131                  */
132                 xchg(&work->flags, IRQ_WORK_BUSY);
133                 work->func(work);
134                 /*
135                  * Clear the BUSY bit and return to the free state if
136                  * no-one else claimed it meanwhile.
137                  */
138                 (void)cmpxchg(&work->flags, IRQ_WORK_BUSY, 0);
139         }
140 }
141 EXPORT_SYMBOL_GPL(irq_work_run);
142
143 /*
144  * Synchronize against the irq_work @entry, ensures the entry is not
145  * currently in use.
146  */
147 void irq_work_sync(struct irq_work *work)
148 {
149         WARN_ON_ONCE(irqs_disabled());
150
151         while (work->flags & IRQ_WORK_BUSY)
152                 cpu_relax();
153 }
154 EXPORT_SYMBOL_GPL(irq_work_sync);