1e360adbeSPeter Zijlstra /* 2e360adbeSPeter Zijlstra * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> 3e360adbeSPeter Zijlstra * 4e360adbeSPeter Zijlstra * Provides a framework for enqueueing and running callbacks from hardirq 5e360adbeSPeter Zijlstra * context. The enqueueing is NMI-safe. 6e360adbeSPeter Zijlstra */ 7e360adbeSPeter Zijlstra 8e360adbeSPeter Zijlstra #include <linux/kernel.h> 9e360adbeSPeter Zijlstra #include <linux/module.h> 10e360adbeSPeter Zijlstra #include <linux/irq_work.h> 11e360adbeSPeter Zijlstra #include <linux/hardirq.h> 12e360adbeSPeter Zijlstra 13e360adbeSPeter Zijlstra /* 14e360adbeSPeter Zijlstra * An entry can be in one of four states: 15e360adbeSPeter Zijlstra * 16e360adbeSPeter Zijlstra * free NULL, 0 -> {claimed} : free to be used 17e360adbeSPeter Zijlstra * claimed NULL, 3 -> {pending} : claimed to be enqueued 18e360adbeSPeter Zijlstra * pending next, 3 -> {busy} : queued, pending callback 19e360adbeSPeter Zijlstra * busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed 20e360adbeSPeter Zijlstra * 21e360adbeSPeter Zijlstra * We use the lower two bits of the next pointer to keep PENDING and BUSY 22e360adbeSPeter Zijlstra * flags. 23e360adbeSPeter Zijlstra */ 24e360adbeSPeter Zijlstra 25e360adbeSPeter Zijlstra #define IRQ_WORK_PENDING 1UL 26e360adbeSPeter Zijlstra #define IRQ_WORK_BUSY 2UL 27e360adbeSPeter Zijlstra #define IRQ_WORK_FLAGS 3UL 28e360adbeSPeter Zijlstra 29e360adbeSPeter Zijlstra static inline bool irq_work_is_set(struct irq_work *entry, int flags) 30e360adbeSPeter Zijlstra { 31e360adbeSPeter Zijlstra return (unsigned long)entry->next & flags; 32e360adbeSPeter Zijlstra } 33e360adbeSPeter Zijlstra 34e360adbeSPeter Zijlstra static inline struct irq_work *irq_work_next(struct irq_work *entry) 35e360adbeSPeter Zijlstra { 36e360adbeSPeter Zijlstra unsigned long next = (unsigned long)entry->next; 37e360adbeSPeter Zijlstra next &= ~IRQ_WORK_FLAGS; 38e360adbeSPeter Zijlstra return (struct irq_work *)next; 39e360adbeSPeter Zijlstra } 40e360adbeSPeter Zijlstra 41e360adbeSPeter Zijlstra static inline struct irq_work *next_flags(struct irq_work *entry, int flags) 42e360adbeSPeter Zijlstra { 43e360adbeSPeter Zijlstra unsigned long next = (unsigned long)entry; 44e360adbeSPeter Zijlstra next |= flags; 45e360adbeSPeter Zijlstra return (struct irq_work *)next; 46e360adbeSPeter Zijlstra } 47e360adbeSPeter Zijlstra 48e360adbeSPeter Zijlstra static DEFINE_PER_CPU(struct irq_work *, irq_work_list); 49e360adbeSPeter Zijlstra 50e360adbeSPeter Zijlstra /* 51e360adbeSPeter Zijlstra * Claim the entry so that no one else will poke at it. 52e360adbeSPeter Zijlstra */ 53e360adbeSPeter Zijlstra static bool irq_work_claim(struct irq_work *entry) 54e360adbeSPeter Zijlstra { 55e360adbeSPeter Zijlstra struct irq_work *next, *nflags; 56e360adbeSPeter Zijlstra 57e360adbeSPeter Zijlstra do { 58e360adbeSPeter Zijlstra next = entry->next; 59e360adbeSPeter Zijlstra if ((unsigned long)next & IRQ_WORK_PENDING) 60e360adbeSPeter Zijlstra return false; 61e360adbeSPeter Zijlstra nflags = next_flags(next, IRQ_WORK_FLAGS); 62e360adbeSPeter Zijlstra } while (cmpxchg(&entry->next, next, nflags) != next); 63e360adbeSPeter Zijlstra 64e360adbeSPeter Zijlstra return true; 65e360adbeSPeter Zijlstra } 66e360adbeSPeter Zijlstra 67e360adbeSPeter Zijlstra 68e360adbeSPeter Zijlstra void __weak arch_irq_work_raise(void) 69e360adbeSPeter Zijlstra { 70e360adbeSPeter Zijlstra /* 71e360adbeSPeter Zijlstra * Lame architectures will get the timer tick callback 72e360adbeSPeter Zijlstra */ 73e360adbeSPeter Zijlstra } 74e360adbeSPeter Zijlstra 75e360adbeSPeter Zijlstra /* 76e360adbeSPeter Zijlstra * Queue the entry and raise the IPI if needed. 77e360adbeSPeter Zijlstra */ 78e360adbeSPeter Zijlstra static void __irq_work_queue(struct irq_work *entry) 79e360adbeSPeter Zijlstra { 80e360adbeSPeter Zijlstra struct irq_work **head, *next; 81e360adbeSPeter Zijlstra 82e360adbeSPeter Zijlstra head = &get_cpu_var(irq_work_list); 83e360adbeSPeter Zijlstra 84e360adbeSPeter Zijlstra do { 85e360adbeSPeter Zijlstra next = *head; 86e360adbeSPeter Zijlstra /* Can assign non-atomic because we keep the flags set. */ 87e360adbeSPeter Zijlstra entry->next = next_flags(next, IRQ_WORK_FLAGS); 88e360adbeSPeter Zijlstra } while (cmpxchg(head, next, entry) != next); 89e360adbeSPeter Zijlstra 90e360adbeSPeter Zijlstra /* The list was empty, raise self-interrupt to start processing. */ 91e360adbeSPeter Zijlstra if (!irq_work_next(entry)) 92e360adbeSPeter Zijlstra arch_irq_work_raise(); 93e360adbeSPeter Zijlstra 94e360adbeSPeter Zijlstra put_cpu_var(irq_work_list); 95e360adbeSPeter Zijlstra } 96e360adbeSPeter Zijlstra 97e360adbeSPeter Zijlstra /* 98e360adbeSPeter Zijlstra * Enqueue the irq_work @entry, returns true on success, failure when the 99e360adbeSPeter Zijlstra * @entry was already enqueued by someone else. 100e360adbeSPeter Zijlstra * 101e360adbeSPeter Zijlstra * Can be re-enqueued while the callback is still in progress. 102e360adbeSPeter Zijlstra */ 103e360adbeSPeter Zijlstra bool irq_work_queue(struct irq_work *entry) 104e360adbeSPeter Zijlstra { 105e360adbeSPeter Zijlstra if (!irq_work_claim(entry)) { 106e360adbeSPeter Zijlstra /* 107e360adbeSPeter Zijlstra * Already enqueued, can't do! 108e360adbeSPeter Zijlstra */ 109e360adbeSPeter Zijlstra return false; 110e360adbeSPeter Zijlstra } 111e360adbeSPeter Zijlstra 112e360adbeSPeter Zijlstra __irq_work_queue(entry); 113e360adbeSPeter Zijlstra return true; 114e360adbeSPeter Zijlstra } 115e360adbeSPeter Zijlstra EXPORT_SYMBOL_GPL(irq_work_queue); 116e360adbeSPeter Zijlstra 117e360adbeSPeter Zijlstra /* 118e360adbeSPeter Zijlstra * Run the irq_work entries on this cpu. Requires to be ran from hardirq 119e360adbeSPeter Zijlstra * context with local IRQs disabled. 120e360adbeSPeter Zijlstra */ 121e360adbeSPeter Zijlstra void irq_work_run(void) 122e360adbeSPeter Zijlstra { 123e360adbeSPeter Zijlstra struct irq_work *list, **head; 124e360adbeSPeter Zijlstra 125e360adbeSPeter Zijlstra head = &__get_cpu_var(irq_work_list); 126e360adbeSPeter Zijlstra if (*head == NULL) 127e360adbeSPeter Zijlstra return; 128e360adbeSPeter Zijlstra 129e360adbeSPeter Zijlstra BUG_ON(!in_irq()); 130e360adbeSPeter Zijlstra BUG_ON(!irqs_disabled()); 131e360adbeSPeter Zijlstra 132e360adbeSPeter Zijlstra list = xchg(head, NULL); 133e360adbeSPeter Zijlstra while (list != NULL) { 134e360adbeSPeter Zijlstra struct irq_work *entry = list; 135e360adbeSPeter Zijlstra 136e360adbeSPeter Zijlstra list = irq_work_next(list); 137e360adbeSPeter Zijlstra 138e360adbeSPeter Zijlstra /* 139e360adbeSPeter Zijlstra * Clear the PENDING bit, after this point the @entry 140e360adbeSPeter Zijlstra * can be re-used. 141e360adbeSPeter Zijlstra */ 142e360adbeSPeter Zijlstra entry->next = next_flags(NULL, IRQ_WORK_BUSY); 143e360adbeSPeter Zijlstra entry->func(entry); 144e360adbeSPeter Zijlstra /* 145e360adbeSPeter Zijlstra * Clear the BUSY bit and return to the free state if 146e360adbeSPeter Zijlstra * no-one else claimed it meanwhile. 147e360adbeSPeter Zijlstra */ 148e360adbeSPeter Zijlstra cmpxchg(&entry->next, next_flags(NULL, IRQ_WORK_BUSY), NULL); 149e360adbeSPeter Zijlstra } 150e360adbeSPeter Zijlstra } 151e360adbeSPeter Zijlstra EXPORT_SYMBOL_GPL(irq_work_run); 152e360adbeSPeter Zijlstra 153e360adbeSPeter Zijlstra /* 154e360adbeSPeter Zijlstra * Synchronize against the irq_work @entry, ensures the entry is not 155e360adbeSPeter Zijlstra * currently in use. 156e360adbeSPeter Zijlstra */ 157e360adbeSPeter Zijlstra void irq_work_sync(struct irq_work *entry) 158e360adbeSPeter Zijlstra { 159e360adbeSPeter Zijlstra WARN_ON_ONCE(irqs_disabled()); 160e360adbeSPeter Zijlstra 161e360adbeSPeter Zijlstra while (irq_work_is_set(entry, IRQ_WORK_BUSY)) 162e360adbeSPeter Zijlstra cpu_relax(); 163e360adbeSPeter Zijlstra } 164e360adbeSPeter Zijlstra EXPORT_SYMBOL_GPL(irq_work_sync); 165