Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 349837
b: refs/heads/master
c: bc6679a
h: refs/heads/master
i:
  349835: de7765c
v: v3
  • Loading branch information
Frederic Weisbecker committed Nov 18, 2012
1 parent d970a99 commit b0d880e
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 21 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8aa2accee41f7045dc904fa41d4475b2f6ffae3e
refs/heads/master: bc6679aef673f9dcb8f718528fc3df49ff661af9
14 changes: 14 additions & 0 deletions trunk/include/linux/irq_work.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@

#include <linux/llist.h>

/*
* An entry can be in one of four states:
*
* free NULL, 0 -> {claimed} : free to be used
* claimed NULL, 3 -> {pending} : claimed to be enqueued
* pending next, 3 -> {busy} : queued, pending callback
* busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed
*/

#define IRQ_WORK_PENDING 1UL
#define IRQ_WORK_BUSY 2UL
#define IRQ_WORK_FLAGS 3UL
#define IRQ_WORK_LAZY 4UL /* Doesn't want IPI, wait for tick */

struct irq_work {
unsigned long flags;
struct llist_node llnode;
Expand Down
47 changes: 27 additions & 20 deletions trunk/kernel/irq_work.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,15 @@
#include <linux/percpu.h>
#include <linux/hardirq.h>
#include <linux/irqflags.h>
#include <linux/sched.h>
#include <linux/tick.h>
#include <linux/cpu.h>
#include <linux/notifier.h>
#include <asm/processor.h>

/*
* An entry can be in one of four states:
*
* free NULL, 0 -> {claimed} : free to be used
* claimed NULL, 3 -> {pending} : claimed to be enqueued
* pending next, 3 -> {busy} : queued, pending callback
* busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed
*/

#define IRQ_WORK_PENDING 1UL
#define IRQ_WORK_BUSY 2UL
#define IRQ_WORK_FLAGS 3UL

static DEFINE_PER_CPU(struct llist_head, irq_work_list);
static DEFINE_PER_CPU(int, irq_work_raised);

/*
* Claim the entry so that no one else will poke at it.
Expand Down Expand Up @@ -69,14 +60,19 @@ void __weak arch_irq_work_raise(void)
*/
static void __irq_work_queue(struct irq_work *work)
{
bool empty;

preempt_disable();

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();
llist_add(&work->llnode, &__get_cpu_var(irq_work_list));

/*
* If the work is not "lazy" or the tick is stopped, raise the irq
* work interrupt (if supported by the arch), otherwise, just wait
* for the next tick.
*/
if (!(work->flags & IRQ_WORK_LAZY) || tick_nohz_tick_stopped()) {
if (!this_cpu_cmpxchg(irq_work_raised, 0, 1))
arch_irq_work_raise();
}

preempt_enable();
}
Expand Down Expand Up @@ -117,10 +113,19 @@ bool irq_work_needs_cpu(void)

static void __irq_work_run(void)
{
unsigned long flags;
struct irq_work *work;
struct llist_head *this_list;
struct llist_node *llnode;


/*
* Reset the "raised" state right before we check the list because
* an NMI may enqueue after we find the list empty from the runner.
*/
__this_cpu_write(irq_work_raised, 0);
barrier();

this_list = &__get_cpu_var(irq_work_list);
if (llist_empty(this_list))
return;
Expand All @@ -140,13 +145,15 @@ static void __irq_work_run(void)
* to claim that work don't rely on us to handle their data
* while we are in the middle of the func.
*/
xchg(&work->flags, IRQ_WORK_BUSY);
flags = work->flags & ~IRQ_WORK_PENDING;
xchg(&work->flags, flags);

work->func(work);
/*
* Clear the BUSY bit and return to the free state if
* no-one else claimed it meanwhile.
*/
(void)cmpxchg(&work->flags, IRQ_WORK_BUSY, 0);
(void)cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY);
}
}

Expand Down

0 comments on commit b0d880e

Please sign in to comment.