aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2011-09-23 12:03:06 -0400
committerThomas Gleixner <tglx@linutronix.de>2011-10-03 09:35:26 -0400
commit31d9d9b6d83030f748d013e61502fa5477e2ac0e (patch)
tree503670b94d594c09daa83c047b426e7b5328aa76
parent60f96b41f71d2a13d1c0a457b8b77958f77142d1 (diff)
genirq: Add support for per-cpu dev_id interrupts
The ARM GIC interrupt controller offers per CPU interrupts (PPIs), which are usually used to connect local timers to each core. Each CPU has its own private interface to the GIC, and only sees the PPIs that are directly connect to it. While these timers are separate devices and have a separate interrupt line to a core, they all use the same IRQ number. For these devices, request_irq() is not the right API as it assumes that an IRQ number is visible by a number of CPUs (through the affinity setting), but makes it very awkward to express that an IRQ number can be handled by all CPUs, and yet be a different interrupt line on each CPU, requiring a different dev_id cookie to be passed back to the handler. The *_percpu_irq() functions is designed to overcome these limitations, by providing a per-cpu dev_id vector: int request_percpu_irq(unsigned int irq, irq_handler_t handler, const char *devname, void __percpu *percpu_dev_id); void free_percpu_irq(unsigned int, void __percpu *); int setup_percpu_irq(unsigned int irq, struct irqaction *new); void remove_percpu_irq(unsigned int irq, struct irqaction *act); void enable_percpu_irq(unsigned int irq); void disable_percpu_irq(unsigned int irq); The API has a number of limitations: - no interrupt sharing - no threading - common handler across all the CPUs Once the interrupt is requested using setup_percpu_irq() or request_percpu_irq(), it must be enabled by each core that wishes its local interrupt to be delivered. Based on an initial patch by Thomas Gleixner. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1316793788-14500-2-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/interrupt.h38
-rw-r--r--include/linux/irq.h16
-rw-r--r--include/linux/irqdesc.h1
-rw-r--r--kernel/irq/chip.c64
-rw-r--r--kernel/irq/internals.h19
-rw-r--r--kernel/irq/irqdesc.c32
-rw-r--r--kernel/irq/manage.c202
-rw-r--r--kernel/irq/settings.h7
8 files changed, 345 insertions, 34 deletions
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index a103732b7588..1cdfd09c8abc 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -95,6 +95,7 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
95 * @flags: flags (see IRQF_* above) 95 * @flags: flags (see IRQF_* above)
96 * @name: name of the device 96 * @name: name of the device
97 * @dev_id: cookie to identify the device 97 * @dev_id: cookie to identify the device
98 * @percpu_dev_id: cookie to identify the device
98 * @next: pointer to the next irqaction for shared interrupts 99 * @next: pointer to the next irqaction for shared interrupts
99 * @irq: interrupt number 100 * @irq: interrupt number
100 * @dir: pointer to the proc/irq/NN/name entry 101 * @dir: pointer to the proc/irq/NN/name entry
@@ -104,17 +105,18 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
104 * @thread_mask: bitmask for keeping track of @thread activity 105 * @thread_mask: bitmask for keeping track of @thread activity
105 */ 106 */
106struct irqaction { 107struct irqaction {
107 irq_handler_t handler; 108 irq_handler_t handler;
108 unsigned long flags; 109 unsigned long flags;
109 void *dev_id; 110 void *dev_id;
110 struct irqaction *next; 111 void __percpu *percpu_dev_id;
111 int irq; 112 struct irqaction *next;
112 irq_handler_t thread_fn; 113 int irq;
113 struct task_struct *thread; 114 irq_handler_t thread_fn;
114 unsigned long thread_flags; 115 struct task_struct *thread;
115 unsigned long thread_mask; 116 unsigned long thread_flags;
116 const char *name; 117 unsigned long thread_mask;
117 struct proc_dir_entry *dir; 118 const char *name;
119 struct proc_dir_entry *dir;
118} ____cacheline_internodealigned_in_smp; 120} ____cacheline_internodealigned_in_smp;
119 121
120extern irqreturn_t no_action(int cpl, void *dev_id); 122extern irqreturn_t no_action(int cpl, void *dev_id);
@@ -136,6 +138,10 @@ extern int __must_check
136request_any_context_irq(unsigned int irq, irq_handler_t handler, 138request_any_context_irq(unsigned int irq, irq_handler_t handler,
137 unsigned long flags, const char *name, void *dev_id); 139 unsigned long flags, const char *name, void *dev_id);
138 140
141extern int __must_check
142request_percpu_irq(unsigned int irq, irq_handler_t handler,
143 const char *devname, void __percpu *percpu_dev_id);
144
139extern void exit_irq_thread(void); 145extern void exit_irq_thread(void);
140#else 146#else
141 147
@@ -164,10 +170,18 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler,
164 return request_irq(irq, handler, flags, name, dev_id); 170 return request_irq(irq, handler, flags, name, dev_id);
165} 171}
166 172
173static inline int __must_check
174request_percpu_irq(unsigned int irq, irq_handler_t handler,
175 const char *devname, void __percpu *percpu_dev_id)
176{
177 return request_irq(irq, handler, 0, devname, percpu_dev_id);
178}
179
167static inline void exit_irq_thread(void) { } 180static inline void exit_irq_thread(void) { }
168#endif 181#endif
169 182
170extern void free_irq(unsigned int, void *); 183extern void free_irq(unsigned int, void *);
184extern void free_percpu_irq(unsigned int, void __percpu *);
171 185
172struct device; 186struct device;
173 187
@@ -207,7 +221,9 @@ extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
207 221
208extern void disable_irq_nosync(unsigned int irq); 222extern void disable_irq_nosync(unsigned int irq);
209extern void disable_irq(unsigned int irq); 223extern void disable_irq(unsigned int irq);
224extern void disable_percpu_irq(unsigned int irq);
210extern void enable_irq(unsigned int irq); 225extern void enable_irq(unsigned int irq);
226extern void enable_percpu_irq(unsigned int irq);
211 227
212/* The following three functions are for the core kernel use only. */ 228/* The following three functions are for the core kernel use only. */
213#ifdef CONFIG_GENERIC_HARDIRQS 229#ifdef CONFIG_GENERIC_HARDIRQS
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 73e31abeba1c..59e49c80cc2c 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -66,6 +66,7 @@ typedef void (*irq_preflow_handler_t)(struct irq_data *data);
66 * IRQ_NO_BALANCING - Interrupt cannot be balanced (affinity set) 66 * IRQ_NO_BALANCING - Interrupt cannot be balanced (affinity set)
67 * IRQ_MOVE_PCNTXT - Interrupt can be migrated from process context 67 * IRQ_MOVE_PCNTXT - Interrupt can be migrated from process context
68 * IRQ_NESTED_TRHEAD - Interrupt nests into another thread 68 * IRQ_NESTED_TRHEAD - Interrupt nests into another thread
69 * IRQ_PER_CPU_DEVID - Dev_id is a per-cpu variable
69 */ 70 */
70enum { 71enum {
71 IRQ_TYPE_NONE = 0x00000000, 72 IRQ_TYPE_NONE = 0x00000000,
@@ -88,12 +89,13 @@ enum {
88 IRQ_MOVE_PCNTXT = (1 << 14), 89 IRQ_MOVE_PCNTXT = (1 << 14),
89 IRQ_NESTED_THREAD = (1 << 15), 90 IRQ_NESTED_THREAD = (1 << 15),
90 IRQ_NOTHREAD = (1 << 16), 91 IRQ_NOTHREAD = (1 << 16),
92 IRQ_PER_CPU_DEVID = (1 << 17),
91}; 93};
92 94
93#define IRQF_MODIFY_MASK \ 95#define IRQF_MODIFY_MASK \
94 (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \ 96 (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
95 IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \ 97 IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
96 IRQ_PER_CPU | IRQ_NESTED_THREAD) 98 IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID)
97 99
98#define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING) 100#define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)
99 101
@@ -367,6 +369,8 @@ enum {
367struct irqaction; 369struct irqaction;
368extern int setup_irq(unsigned int irq, struct irqaction *new); 370extern int setup_irq(unsigned int irq, struct irqaction *new);
369extern void remove_irq(unsigned int irq, struct irqaction *act); 371extern void remove_irq(unsigned int irq, struct irqaction *act);
372extern int setup_percpu_irq(unsigned int irq, struct irqaction *new);
373extern void remove_percpu_irq(unsigned int irq, struct irqaction *act);
370 374
371extern void irq_cpu_online(void); 375extern void irq_cpu_online(void);
372extern void irq_cpu_offline(void); 376extern void irq_cpu_offline(void);
@@ -394,6 +398,7 @@ extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc);
394extern void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc); 398extern void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc);
395extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc); 399extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc);
396extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc); 400extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc);
401extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);
397extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc); 402extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
398extern void handle_nested_irq(unsigned int irq); 403extern void handle_nested_irq(unsigned int irq);
399 404
@@ -422,6 +427,8 @@ static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *c
422 irq_set_chip_and_handler_name(irq, chip, handle, NULL); 427 irq_set_chip_and_handler_name(irq, chip, handle, NULL);
423} 428}
424 429
430extern int irq_set_percpu_devid(unsigned int irq);
431
425extern void 432extern void
426__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, 433__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
427 const char *name); 434 const char *name);
@@ -483,6 +490,13 @@ static inline void irq_set_nested_thread(unsigned int irq, bool nest)
483 irq_clear_status_flags(irq, IRQ_NESTED_THREAD); 490 irq_clear_status_flags(irq, IRQ_NESTED_THREAD);
484} 491}
485 492
493static inline void irq_set_percpu_devid_flags(unsigned int irq)
494{
495 irq_set_status_flags(irq,
496 IRQ_NOAUTOEN | IRQ_PER_CPU | IRQ_NOTHREAD |
497 IRQ_NOPROBE | IRQ_PER_CPU_DEVID);
498}
499
486/* Handle dynamic irq creation and destruction */ 500/* Handle dynamic irq creation and destruction */
487extern unsigned int create_irq_nr(unsigned int irq_want, int node); 501extern unsigned int create_irq_nr(unsigned int irq_want, int node);
488extern int create_irq(void); 502extern int create_irq(void);
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 150134ac709a..6b69c2c9dff1 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -53,6 +53,7 @@ struct irq_desc {
53 unsigned long last_unhandled; /* Aging timer for unhandled count */ 53 unsigned long last_unhandled; /* Aging timer for unhandled count */
54 unsigned int irqs_unhandled; 54 unsigned int irqs_unhandled;
55 raw_spinlock_t lock; 55 raw_spinlock_t lock;
56 struct cpumask *percpu_enabled;
56#ifdef CONFIG_SMP 57#ifdef CONFIG_SMP
57 const struct cpumask *affinity_hint; 58 const struct cpumask *affinity_hint;
58 struct irq_affinity_notify *affinity_notify; 59 struct irq_affinity_notify *affinity_notify;
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index dc5114b4c16c..f7c543a801d9 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -26,7 +26,7 @@
26int irq_set_chip(unsigned int irq, struct irq_chip *chip) 26int irq_set_chip(unsigned int irq, struct irq_chip *chip)
27{ 27{
28 unsigned long flags; 28 unsigned long flags;
29 struct irq_desc *desc = irq_get_desc_lock(irq, &flags); 29 struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
30 30
31 if (!desc) 31 if (!desc)
32 return -EINVAL; 32 return -EINVAL;
@@ -54,7 +54,7 @@ EXPORT_SYMBOL(irq_set_chip);
54int irq_set_irq_type(unsigned int irq, unsigned int type) 54int irq_set_irq_type(unsigned int irq, unsigned int type)
55{ 55{
56 unsigned long flags; 56 unsigned long flags;
57 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); 57 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
58 int ret = 0; 58 int ret = 0;
59 59
60 if (!desc) 60 if (!desc)
@@ -78,7 +78,7 @@ EXPORT_SYMBOL(irq_set_irq_type);
78int irq_set_handler_data(unsigned int irq, void *data) 78int irq_set_handler_data(unsigned int irq, void *data)
79{ 79{
80 unsigned long flags; 80 unsigned long flags;
81 struct irq_desc *desc = irq_get_desc_lock(irq, &flags); 81 struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
82 82
83 if (!desc) 83 if (!desc)
84 return -EINVAL; 84 return -EINVAL;
@@ -98,7 +98,7 @@ EXPORT_SYMBOL(irq_set_handler_data);
98int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) 98int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)
99{ 99{
100 unsigned long flags; 100 unsigned long flags;
101 struct irq_desc *desc = irq_get_desc_lock(irq, &flags); 101 struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
102 102
103 if (!desc) 103 if (!desc)
104 return -EINVAL; 104 return -EINVAL;
@@ -119,7 +119,7 @@ int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)
119int irq_set_chip_data(unsigned int irq, void *data) 119int irq_set_chip_data(unsigned int irq, void *data)
120{ 120{
121 unsigned long flags; 121 unsigned long flags;
122 struct irq_desc *desc = irq_get_desc_lock(irq, &flags); 122 struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
123 123
124 if (!desc) 124 if (!desc)
125 return -EINVAL; 125 return -EINVAL;
@@ -204,6 +204,24 @@ void irq_disable(struct irq_desc *desc)
204 } 204 }
205} 205}
206 206
207void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu)
208{
209 if (desc->irq_data.chip->irq_enable)
210 desc->irq_data.chip->irq_enable(&desc->irq_data);
211 else
212 desc->irq_data.chip->irq_unmask(&desc->irq_data);
213 cpumask_set_cpu(cpu, desc->percpu_enabled);
214}
215
216void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu)
217{
218 if (desc->irq_data.chip->irq_disable)
219 desc->irq_data.chip->irq_disable(&desc->irq_data);
220 else
221 desc->irq_data.chip->irq_mask(&desc->irq_data);
222 cpumask_clear_cpu(cpu, desc->percpu_enabled);
223}
224
207static inline void mask_ack_irq(struct irq_desc *desc) 225static inline void mask_ack_irq(struct irq_desc *desc)
208{ 226{
209 if (desc->irq_data.chip->irq_mask_ack) 227 if (desc->irq_data.chip->irq_mask_ack)
@@ -544,12 +562,44 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
544 chip->irq_eoi(&desc->irq_data); 562 chip->irq_eoi(&desc->irq_data);
545} 563}
546 564
565/**
566 * handle_percpu_devid_irq - Per CPU local irq handler with per cpu dev ids
567 * @irq: the interrupt number
568 * @desc: the interrupt description structure for this irq
569 *
570 * Per CPU interrupts on SMP machines without locking requirements. Same as
571 * handle_percpu_irq() above but with the following extras:
572 *
573 * action->percpu_dev_id is a pointer to percpu variables which
574 * contain the real device id for the cpu on which this handler is
575 * called
576 */
577void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc)
578{
579 struct irq_chip *chip = irq_desc_get_chip(desc);
580 struct irqaction *action = desc->action;
581 void *dev_id = __this_cpu_ptr(action->percpu_dev_id);
582 irqreturn_t res;
583
584 kstat_incr_irqs_this_cpu(irq, desc);
585
586 if (chip->irq_ack)
587 chip->irq_ack(&desc->irq_data);
588
589 trace_irq_handler_entry(irq, action);
590 res = action->handler(irq, dev_id);
591 trace_irq_handler_exit(irq, action, res);
592
593 if (chip->irq_eoi)
594 chip->irq_eoi(&desc->irq_data);
595}
596
547void 597void
548__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, 598__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
549 const char *name) 599 const char *name)
550{ 600{
551 unsigned long flags; 601 unsigned long flags;
552 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); 602 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
553 603
554 if (!desc) 604 if (!desc)
555 return; 605 return;
@@ -593,7 +643,7 @@ irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
593void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) 643void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
594{ 644{
595 unsigned long flags; 645 unsigned long flags;
596 struct irq_desc *desc = irq_get_desc_lock(irq, &flags); 646 struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
597 647
598 if (!desc) 648 if (!desc)
599 return; 649 return;
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 6546431447d7..a73dd6c7372d 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -71,6 +71,8 @@ extern int irq_startup(struct irq_desc *desc);
71extern void irq_shutdown(struct irq_desc *desc); 71extern void irq_shutdown(struct irq_desc *desc);
72extern void irq_enable(struct irq_desc *desc); 72extern void irq_enable(struct irq_desc *desc);
73extern void irq_disable(struct irq_desc *desc); 73extern void irq_disable(struct irq_desc *desc);
74extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
75extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
74extern void mask_irq(struct irq_desc *desc); 76extern void mask_irq(struct irq_desc *desc);
75extern void unmask_irq(struct irq_desc *desc); 77extern void unmask_irq(struct irq_desc *desc);
76 78
@@ -114,14 +116,21 @@ static inline void chip_bus_sync_unlock(struct irq_desc *desc)
114 desc->irq_data.chip->irq_bus_sync_unlock(&desc->irq_data); 116 desc->irq_data.chip->irq_bus_sync_unlock(&desc->irq_data);
115} 117}
116 118
119#define _IRQ_DESC_CHECK (1 << 0)
120#define _IRQ_DESC_PERCPU (1 << 1)
121
122#define IRQ_GET_DESC_CHECK_GLOBAL (_IRQ_DESC_CHECK)
123#define IRQ_GET_DESC_CHECK_PERCPU (_IRQ_DESC_CHECK | _IRQ_DESC_PERCPU)
124
117struct irq_desc * 125struct irq_desc *
118__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus); 126__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus,
127 unsigned int check);
119void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus); 128void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus);
120 129
121static inline struct irq_desc * 130static inline struct irq_desc *
122irq_get_desc_buslock(unsigned int irq, unsigned long *flags) 131irq_get_desc_buslock(unsigned int irq, unsigned long *flags, unsigned int check)
123{ 132{
124 return __irq_get_desc_lock(irq, flags, true); 133 return __irq_get_desc_lock(irq, flags, true, check);
125} 134}
126 135
127static inline void 136static inline void
@@ -131,9 +140,9 @@ irq_put_desc_busunlock(struct irq_desc *desc, unsigned long flags)
131} 140}
132 141
133static inline struct irq_desc * 142static inline struct irq_desc *
134irq_get_desc_lock(unsigned int irq, unsigned long *flags) 143irq_get_desc_lock(unsigned int irq, unsigned long *flags, unsigned int check)
135{ 144{
136 return __irq_get_desc_lock(irq, flags, false); 145 return __irq_get_desc_lock(irq, flags, false, check);
137} 146}
138 147
139static inline void 148static inline void
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 039b889ea053..1550e8447a16 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -424,11 +424,22 @@ unsigned int irq_get_next_irq(unsigned int offset)
424} 424}
425 425
426struct irq_desc * 426struct irq_desc *
427__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus) 427__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus,
428 unsigned int check)
428{ 429{
429 struct irq_desc *desc = irq_to_desc(irq); 430 struct irq_desc *desc = irq_to_desc(irq);
430 431
431 if (desc) { 432 if (desc) {
433 if (check & _IRQ_DESC_CHECK) {
434 if ((check & _IRQ_DESC_PERCPU) &&
435 !irq_settings_is_per_cpu_devid(desc))
436 return NULL;
437
438 if (!(check & _IRQ_DESC_PERCPU) &&
439 irq_settings_is_per_cpu_devid(desc))
440 return NULL;
441 }
442
432 if (bus) 443 if (bus)
433 chip_bus_lock(desc); 444 chip_bus_lock(desc);
434 raw_spin_lock_irqsave(&desc->lock, *flags); 445 raw_spin_lock_irqsave(&desc->lock, *flags);
@@ -443,6 +454,25 @@ void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus)
443 chip_bus_sync_unlock(desc); 454 chip_bus_sync_unlock(desc);
444} 455}
445 456
457int irq_set_percpu_devid(unsigned int irq)
458{
459 struct irq_desc *desc = irq_to_desc(irq);
460
461 if (!desc)
462 return -EINVAL;
463
464 if (desc->percpu_enabled)
465 return -EINVAL;
466
467 desc->percpu_enabled = kzalloc(sizeof(*desc->percpu_enabled), GFP_KERNEL);
468
469 if (!desc->percpu_enabled)
470 return -ENOMEM;
471
472 irq_set_percpu_devid_flags(irq);
473 return 0;
474}
475
446/** 476/**
447 * dynamic_irq_cleanup - cleanup a dynamically allocated irq 477 * dynamic_irq_cleanup - cleanup a dynamically allocated irq
448 * @irq: irq number to initialize 478 * @irq: irq number to initialize
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 7e1a3ed1e61a..7b4b156d065c 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -195,7 +195,7 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *mask)
195int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) 195int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m)
196{ 196{
197 unsigned long flags; 197 unsigned long flags;
198 struct irq_desc *desc = irq_get_desc_lock(irq, &flags); 198 struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
199 199
200 if (!desc) 200 if (!desc)
201 return -EINVAL; 201 return -EINVAL;
@@ -356,7 +356,7 @@ void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
356static int __disable_irq_nosync(unsigned int irq) 356static int __disable_irq_nosync(unsigned int irq)
357{ 357{
358 unsigned long flags; 358 unsigned long flags;
359 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); 359 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
360 360
361 if (!desc) 361 if (!desc)
362 return -EINVAL; 362 return -EINVAL;
@@ -448,7 +448,7 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
448void enable_irq(unsigned int irq) 448void enable_irq(unsigned int irq)
449{ 449{
450 unsigned long flags; 450 unsigned long flags;
451 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); 451 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
452 452
453 if (!desc) 453 if (!desc)
454 return; 454 return;
@@ -491,7 +491,7 @@ static int set_irq_wake_real(unsigned int irq, unsigned int on)
491int irq_set_irq_wake(unsigned int irq, unsigned int on) 491int irq_set_irq_wake(unsigned int irq, unsigned int on)
492{ 492{
493 unsigned long flags; 493 unsigned long flags;
494 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); 494 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
495 int ret = 0; 495 int ret = 0;
496 496
497 if (!desc) 497 if (!desc)
@@ -532,7 +532,7 @@ EXPORT_SYMBOL(irq_set_irq_wake);
532int can_request_irq(unsigned int irq, unsigned long irqflags) 532int can_request_irq(unsigned int irq, unsigned long irqflags)
533{ 533{
534 unsigned long flags; 534 unsigned long flags;
535 struct irq_desc *desc = irq_get_desc_lock(irq, &flags); 535 struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
536 int canrequest = 0; 536 int canrequest = 0;
537 537
538 if (!desc) 538 if (!desc)
@@ -1121,6 +1121,8 @@ int setup_irq(unsigned int irq, struct irqaction *act)
1121 int retval; 1121 int retval;
1122 struct irq_desc *desc = irq_to_desc(irq); 1122 struct irq_desc *desc = irq_to_desc(irq);
1123 1123
1124 if (WARN_ON(irq_settings_is_per_cpu_devid(desc)))
1125 return -EINVAL;
1124 chip_bus_lock(desc); 1126 chip_bus_lock(desc);
1125 retval = __setup_irq(irq, desc, act); 1127 retval = __setup_irq(irq, desc, act);
1126 chip_bus_sync_unlock(desc); 1128 chip_bus_sync_unlock(desc);
@@ -1129,7 +1131,7 @@ int setup_irq(unsigned int irq, struct irqaction *act)
1129} 1131}
1130EXPORT_SYMBOL_GPL(setup_irq); 1132EXPORT_SYMBOL_GPL(setup_irq);
1131 1133
1132 /* 1134/*
1133 * Internal function to unregister an irqaction - used to free 1135 * Internal function to unregister an irqaction - used to free
1134 * regular and special interrupts that are part of the architecture. 1136 * regular and special interrupts that are part of the architecture.
1135 */ 1137 */
@@ -1227,7 +1229,10 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
1227 */ 1229 */
1228void remove_irq(unsigned int irq, struct irqaction *act) 1230void remove_irq(unsigned int irq, struct irqaction *act)
1229{ 1231{
1230 __free_irq(irq, act->dev_id); 1232 struct irq_desc *desc = irq_to_desc(irq);
1233
1234 if (desc && !WARN_ON(irq_settings_is_per_cpu_devid(desc)))
1235 __free_irq(irq, act->dev_id);
1231} 1236}
1232EXPORT_SYMBOL_GPL(remove_irq); 1237EXPORT_SYMBOL_GPL(remove_irq);
1233 1238
@@ -1249,7 +1254,7 @@ void free_irq(unsigned int irq, void *dev_id)
1249{ 1254{
1250 struct irq_desc *desc = irq_to_desc(irq); 1255 struct irq_desc *desc = irq_to_desc(irq);
1251 1256
1252 if (!desc) 1257 if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
1253 return; 1258 return;
1254 1259
1255#ifdef CONFIG_SMP 1260#ifdef CONFIG_SMP
@@ -1327,7 +1332,8 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
1327 if (!desc) 1332 if (!desc)
1328 return -EINVAL; 1333 return -EINVAL;
1329 1334
1330 if (!irq_settings_can_request(desc)) 1335 if (!irq_settings_can_request(desc) ||
1336 WARN_ON(irq_settings_is_per_cpu_devid(desc)))
1331 return -EINVAL; 1337 return -EINVAL;
1332 1338
1333 if (!handler) { 1339 if (!handler) {
@@ -1412,3 +1418,181 @@ int request_any_context_irq(unsigned int irq, irq_handler_t handler,
1412 return !ret ? IRQC_IS_HARDIRQ : ret; 1418 return !ret ? IRQC_IS_HARDIRQ : ret;
1413} 1419}
1414EXPORT_SYMBOL_GPL(request_any_context_irq); 1420EXPORT_SYMBOL_GPL(request_any_context_irq);
1421
1422void enable_percpu_irq(unsigned int irq)
1423{
1424 unsigned int cpu = smp_processor_id();
1425 unsigned long flags;
1426 struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU);
1427
1428 if (!desc)
1429 return;
1430
1431 irq_percpu_enable(desc, cpu);
1432 irq_put_desc_unlock(desc, flags);
1433}
1434
1435void disable_percpu_irq(unsigned int irq)
1436{
1437 unsigned int cpu = smp_processor_id();
1438 unsigned long flags;
1439 struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU);
1440
1441 if (!desc)
1442 return;
1443
1444 irq_percpu_disable(desc, cpu);
1445 irq_put_desc_unlock(desc, flags);
1446}
1447
1448/*
1449 * Internal function to unregister a percpu irqaction.
1450 */
1451static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_id)
1452{
1453 struct irq_desc *desc = irq_to_desc(irq);
1454 struct irqaction *action;
1455 unsigned long flags;
1456
1457 WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
1458
1459 if (!desc)
1460 return NULL;
1461
1462 raw_spin_lock_irqsave(&desc->lock, flags);
1463
1464 action = desc->action;
1465 if (!action || action->percpu_dev_id != dev_id) {
1466 WARN(1, "Trying to free already-free IRQ %d\n", irq);
1467 goto bad;
1468 }
1469
1470 if (!cpumask_empty(desc->percpu_enabled)) {
1471 WARN(1, "percpu IRQ %d still enabled on CPU%d!\n",
1472 irq, cpumask_first(desc->percpu_enabled));
1473 goto bad;
1474 }
1475
1476 /* Found it - now remove it from the list of entries: */
1477 desc->action = NULL;
1478
1479 raw_spin_unlock_irqrestore(&desc->lock, flags);
1480
1481 unregister_handler_proc(irq, action);
1482
1483 module_put(desc->owner);
1484 return action;
1485
1486bad:
1487 raw_spin_unlock_irqrestore(&desc->lock, flags);
1488 return NULL;
1489}
1490
1491/**
1492 * remove_percpu_irq - free a per-cpu interrupt
1493 * @irq: Interrupt line to free
1494 * @act: irqaction for the interrupt
1495 *
1496 * Used to remove interrupts statically setup by the early boot process.
1497 */
1498void remove_percpu_irq(unsigned int irq, struct irqaction *act)
1499{
1500 struct irq_desc *desc = irq_to_desc(irq);
1501
1502 if (desc && irq_settings_is_per_cpu_devid(desc))
1503 __free_percpu_irq(irq, act->percpu_dev_id);
1504}
1505
1506/**
1507 * free_percpu_irq - free an interrupt allocated with request_percpu_irq
1508 * @irq: Interrupt line to free
1509 * @dev_id: Device identity to free
1510 *
1511 * Remove a percpu interrupt handler. The handler is removed, but
1512 * the interrupt line is not disabled. This must be done on each
1513 * CPU before calling this function. The function does not return
1514 * until any executing interrupts for this IRQ have completed.
1515 *
1516 * This function must not be called from interrupt context.
1517 */
1518void free_percpu_irq(unsigned int irq, void __percpu *dev_id)
1519{
1520 struct irq_desc *desc = irq_to_desc(irq);
1521
1522 if (!desc || !irq_settings_is_per_cpu_devid(desc))
1523 return;
1524
1525 chip_bus_lock(desc);
1526 kfree(__free_percpu_irq(irq, dev_id));
1527 chip_bus_sync_unlock(desc);
1528}
1529
1530/**
1531 * setup_percpu_irq - setup a per-cpu interrupt
1532 * @irq: Interrupt line to setup
1533 * @act: irqaction for the interrupt
1534 *
1535 * Used to statically setup per-cpu interrupts in the early boot process.
1536 */
1537int setup_percpu_irq(unsigned int irq, struct irqaction *act)
1538{
1539 struct irq_desc *desc = irq_to_desc(irq);
1540 int retval;
1541
1542 if (!desc || !irq_settings_is_per_cpu_devid(desc))
1543 return -EINVAL;
1544 chip_bus_lock(desc);
1545 retval = __setup_irq(irq, desc, act);
1546 chip_bus_sync_unlock(desc);
1547
1548 return retval;
1549}
1550
1551/**
1552 * request_percpu_irq - allocate a percpu interrupt line
1553 * @irq: Interrupt line to allocate
1554 * @handler: Function to be called when the IRQ occurs.
1555 * @devname: An ascii name for the claiming device
1556 * @dev_id: A percpu cookie passed back to the handler function
1557 *
1558 * This call allocates interrupt resources, but doesn't
1559 * automatically enable the interrupt. It has to be done on each
1560 * CPU using enable_percpu_irq().
1561 *
1562 * Dev_id must be globally unique. It is a per-cpu variable, and
1563 * the handler gets called with the interrupted CPU's instance of
1564 * that variable.
1565 */
1566int request_percpu_irq(unsigned int irq, irq_handler_t handler,
1567 const char *devname, void __percpu *dev_id)
1568{
1569 struct irqaction *action;
1570 struct irq_desc *desc;
1571 int retval;
1572
1573 if (!dev_id)
1574 return -EINVAL;
1575
1576 desc = irq_to_desc(irq);
1577 if (!desc || !irq_settings_can_request(desc) ||
1578 !irq_settings_is_per_cpu_devid(desc))
1579 return -EINVAL;
1580
1581 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
1582 if (!action)
1583 return -ENOMEM;
1584
1585 action->handler = handler;
1586 action->flags = IRQF_PERCPU;
1587 action->name = devname;
1588 action->percpu_dev_id = dev_id;
1589
1590 chip_bus_lock(desc);
1591 retval = __setup_irq(irq, desc, action);
1592 chip_bus_sync_unlock(desc);
1593
1594 if (retval)
1595 kfree(action);
1596
1597 return retval;
1598}
diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h
index f1667833d444..1162f1030f18 100644
--- a/kernel/irq/settings.h
+++ b/kernel/irq/settings.h
@@ -13,6 +13,7 @@ enum {
13 _IRQ_MOVE_PCNTXT = IRQ_MOVE_PCNTXT, 13 _IRQ_MOVE_PCNTXT = IRQ_MOVE_PCNTXT,
14 _IRQ_NO_BALANCING = IRQ_NO_BALANCING, 14 _IRQ_NO_BALANCING = IRQ_NO_BALANCING,
15 _IRQ_NESTED_THREAD = IRQ_NESTED_THREAD, 15 _IRQ_NESTED_THREAD = IRQ_NESTED_THREAD,
16 _IRQ_PER_CPU_DEVID = IRQ_PER_CPU_DEVID,
16 _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK, 17 _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK,
17}; 18};
18 19
@@ -24,6 +25,7 @@ enum {
24#define IRQ_NOTHREAD GOT_YOU_MORON 25#define IRQ_NOTHREAD GOT_YOU_MORON
25#define IRQ_NOAUTOEN GOT_YOU_MORON 26#define IRQ_NOAUTOEN GOT_YOU_MORON
26#define IRQ_NESTED_THREAD GOT_YOU_MORON 27#define IRQ_NESTED_THREAD GOT_YOU_MORON
28#define IRQ_PER_CPU_DEVID GOT_YOU_MORON
27#undef IRQF_MODIFY_MASK 29#undef IRQF_MODIFY_MASK
28#define IRQF_MODIFY_MASK GOT_YOU_MORON 30#define IRQF_MODIFY_MASK GOT_YOU_MORON
29 31
@@ -39,6 +41,11 @@ static inline bool irq_settings_is_per_cpu(struct irq_desc *desc)
39 return desc->status_use_accessors & _IRQ_PER_CPU; 41 return desc->status_use_accessors & _IRQ_PER_CPU;
40} 42}
41 43
44static inline bool irq_settings_is_per_cpu_devid(struct irq_desc *desc)
45{
46 return desc->status_use_accessors & _IRQ_PER_CPU_DEVID;
47}
48
42static inline void irq_settings_set_per_cpu(struct irq_desc *desc) 49static inline void irq_settings_set_per_cpu(struct irq_desc *desc)
43{ 50{
44 desc->status_use_accessors |= _IRQ_PER_CPU; 51 desc->status_use_accessors |= _IRQ_PER_CPU;