aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;