diff options
| -rw-r--r-- | drivers/xen/events.c | 2 | ||||
| -rw-r--r-- | include/linux/interrupt.h | 41 | ||||
| -rw-r--r-- | include/linux/irq.h | 18 | ||||
| -rw-r--r-- | include/linux/irqdesc.h | 1 | ||||
| -rw-r--r-- | kernel/irq/chip.c | 64 | ||||
| -rw-r--r-- | kernel/irq/internals.h | 19 | ||||
| -rw-r--r-- | kernel/irq/irqdesc.c | 32 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 218 | ||||
| -rw-r--r-- | kernel/irq/pm.c | 48 | ||||
| -rw-r--r-- | kernel/irq/settings.h | 7 |
10 files changed, 408 insertions, 42 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 7a55b292bf39..0eb8a57cc808 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
| @@ -1049,7 +1049,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi, | |||
| 1049 | if (irq < 0) | 1049 | if (irq < 0) |
| 1050 | return irq; | 1050 | return irq; |
| 1051 | 1051 | ||
| 1052 | irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME; | 1052 | irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME | IRQF_EARLY_RESUME; |
| 1053 | retval = request_irq(irq, handler, irqflags, devname, dev_id); | 1053 | retval = request_irq(irq, handler, irqflags, devname, dev_id); |
| 1054 | if (retval != 0) { | 1054 | if (retval != 0) { |
| 1055 | unbind_from_irq(irq); | 1055 | unbind_from_irq(irq); |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index a103732b7588..a64b00e286f5 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
| @@ -59,6 +59,8 @@ | |||
| 59 | * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend | 59 | * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend |
| 60 | * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set | 60 | * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set |
| 61 | * IRQF_NO_THREAD - Interrupt cannot be threaded | 61 | * IRQF_NO_THREAD - Interrupt cannot be threaded |
| 62 | * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device | ||
| 63 | * resume time. | ||
| 62 | */ | 64 | */ |
| 63 | #define IRQF_DISABLED 0x00000020 | 65 | #define IRQF_DISABLED 0x00000020 |
| 64 | #define IRQF_SAMPLE_RANDOM 0x00000040 | 66 | #define IRQF_SAMPLE_RANDOM 0x00000040 |
| @@ -72,6 +74,7 @@ | |||
| 72 | #define IRQF_NO_SUSPEND 0x00004000 | 74 | #define IRQF_NO_SUSPEND 0x00004000 |
| 73 | #define IRQF_FORCE_RESUME 0x00008000 | 75 | #define IRQF_FORCE_RESUME 0x00008000 |
| 74 | #define IRQF_NO_THREAD 0x00010000 | 76 | #define IRQF_NO_THREAD 0x00010000 |
| 77 | #define IRQF_EARLY_RESUME 0x00020000 | ||
| 75 | 78 | ||
| 76 | #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) | 79 | #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) |
| 77 | 80 | ||
| @@ -95,6 +98,7 @@ typedef irqreturn_t (*irq_handler_t)(int, void *); | |||
| 95 | * @flags: flags (see IRQF_* above) | 98 | * @flags: flags (see IRQF_* above) |
| 96 | * @name: name of the device | 99 | * @name: name of the device |
| 97 | * @dev_id: cookie to identify the device | 100 | * @dev_id: cookie to identify the device |
| 101 | * @percpu_dev_id: cookie to identify the device | ||
| 98 | * @next: pointer to the next irqaction for shared interrupts | 102 | * @next: pointer to the next irqaction for shared interrupts |
| 99 | * @irq: interrupt number | 103 | * @irq: interrupt number |
| 100 | * @dir: pointer to the proc/irq/NN/name entry | 104 | * @dir: pointer to the proc/irq/NN/name entry |
| @@ -104,17 +108,18 @@ typedef irqreturn_t (*irq_handler_t)(int, void *); | |||
| 104 | * @thread_mask: bitmask for keeping track of @thread activity | 108 | * @thread_mask: bitmask for keeping track of @thread activity |
| 105 | */ | 109 | */ |
| 106 | struct irqaction { | 110 | struct irqaction { |
| 107 | irq_handler_t handler; | 111 | irq_handler_t handler; |
| 108 | unsigned long flags; | 112 | unsigned long flags; |
| 109 | void *dev_id; | 113 | void *dev_id; |
| 110 | struct irqaction *next; | 114 | void __percpu *percpu_dev_id; |
| 111 | int irq; | 115 | struct irqaction *next; |
| 112 | irq_handler_t thread_fn; | 116 | int irq; |
| 113 | struct task_struct *thread; | 117 | irq_handler_t thread_fn; |
| 114 | unsigned long thread_flags; | 118 | struct task_struct *thread; |
| 115 | unsigned long thread_mask; | 119 | unsigned long thread_flags; |
| 116 | const char *name; | 120 | unsigned long thread_mask; |
| 117 | struct proc_dir_entry *dir; | 121 | const char *name; |
| 122 | struct proc_dir_entry *dir; | ||
| 118 | } ____cacheline_internodealigned_in_smp; | 123 | } ____cacheline_internodealigned_in_smp; |
| 119 | 124 | ||
| 120 | extern irqreturn_t no_action(int cpl, void *dev_id); | 125 | extern irqreturn_t no_action(int cpl, void *dev_id); |
| @@ -136,6 +141,10 @@ extern int __must_check | |||
| 136 | request_any_context_irq(unsigned int irq, irq_handler_t handler, | 141 | request_any_context_irq(unsigned int irq, irq_handler_t handler, |
| 137 | unsigned long flags, const char *name, void *dev_id); | 142 | unsigned long flags, const char *name, void *dev_id); |
| 138 | 143 | ||
| 144 | extern int __must_check | ||
| 145 | request_percpu_irq(unsigned int irq, irq_handler_t handler, | ||
| 146 | const char *devname, void __percpu *percpu_dev_id); | ||
| 147 | |||
| 139 | extern void exit_irq_thread(void); | 148 | extern void exit_irq_thread(void); |
| 140 | #else | 149 | #else |
| 141 | 150 | ||
| @@ -164,10 +173,18 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler, | |||
| 164 | return request_irq(irq, handler, flags, name, dev_id); | 173 | return request_irq(irq, handler, flags, name, dev_id); |
| 165 | } | 174 | } |
| 166 | 175 | ||
| 176 | static inline int __must_check | ||
| 177 | request_percpu_irq(unsigned int irq, irq_handler_t handler, | ||
| 178 | const char *devname, void __percpu *percpu_dev_id) | ||
| 179 | { | ||
| 180 | return request_irq(irq, handler, 0, devname, percpu_dev_id); | ||
| 181 | } | ||
| 182 | |||
| 167 | static inline void exit_irq_thread(void) { } | 183 | static inline void exit_irq_thread(void) { } |
| 168 | #endif | 184 | #endif |
| 169 | 185 | ||
| 170 | extern void free_irq(unsigned int, void *); | 186 | extern void free_irq(unsigned int, void *); |
| 187 | extern void free_percpu_irq(unsigned int, void __percpu *); | ||
| 171 | 188 | ||
| 172 | struct device; | 189 | struct device; |
| 173 | 190 | ||
| @@ -207,7 +224,9 @@ extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id); | |||
| 207 | 224 | ||
| 208 | extern void disable_irq_nosync(unsigned int irq); | 225 | extern void disable_irq_nosync(unsigned int irq); |
| 209 | extern void disable_irq(unsigned int irq); | 226 | extern void disable_irq(unsigned int irq); |
| 227 | extern void disable_percpu_irq(unsigned int irq); | ||
| 210 | extern void enable_irq(unsigned int irq); | 228 | extern void enable_irq(unsigned int irq); |
| 229 | extern void enable_percpu_irq(unsigned int irq, unsigned int type); | ||
| 211 | 230 | ||
| 212 | /* The following three functions are for the core kernel use only. */ | 231 | /* The following three functions are for the core kernel use only. */ |
| 213 | #ifdef CONFIG_GENERIC_HARDIRQS | 232 | #ifdef CONFIG_GENERIC_HARDIRQS |
diff --git a/include/linux/irq.h b/include/linux/irq.h index 59517300a315..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 | */ |
| 70 | enum { | 71 | enum { |
| 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 | ||
| @@ -336,12 +338,14 @@ struct irq_chip { | |||
| 336 | * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path | 338 | * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path |
| 337 | * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks | 339 | * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks |
| 338 | * when irq enabled | 340 | * when irq enabled |
| 341 | * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip | ||
| 339 | */ | 342 | */ |
| 340 | enum { | 343 | enum { |
| 341 | IRQCHIP_SET_TYPE_MASKED = (1 << 0), | 344 | IRQCHIP_SET_TYPE_MASKED = (1 << 0), |
| 342 | IRQCHIP_EOI_IF_HANDLED = (1 << 1), | 345 | IRQCHIP_EOI_IF_HANDLED = (1 << 1), |
| 343 | IRQCHIP_MASK_ON_SUSPEND = (1 << 2), | 346 | IRQCHIP_MASK_ON_SUSPEND = (1 << 2), |
| 344 | IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), | 347 | IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), |
| 348 | IRQCHIP_SKIP_SET_WAKE = (1 << 4), | ||
| 345 | }; | 349 | }; |
| 346 | 350 | ||
| 347 | /* This include will go away once we isolated irq_desc usage to core code */ | 351 | /* This include will go away once we isolated irq_desc usage to core code */ |
| @@ -365,6 +369,8 @@ enum { | |||
| 365 | struct irqaction; | 369 | struct irqaction; |
| 366 | extern int setup_irq(unsigned int irq, struct irqaction *new); | 370 | extern int setup_irq(unsigned int irq, struct irqaction *new); |
| 367 | extern void remove_irq(unsigned int irq, struct irqaction *act); | 371 | extern void remove_irq(unsigned int irq, struct irqaction *act); |
| 372 | extern int setup_percpu_irq(unsigned int irq, struct irqaction *new); | ||
| 373 | extern void remove_percpu_irq(unsigned int irq, struct irqaction *act); | ||
| 368 | 374 | ||
| 369 | extern void irq_cpu_online(void); | 375 | extern void irq_cpu_online(void); |
| 370 | extern void irq_cpu_offline(void); | 376 | extern void irq_cpu_offline(void); |
| @@ -392,6 +398,7 @@ extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc); | |||
| 392 | extern void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc); | 398 | extern void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc); |
| 393 | extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc); | 399 | extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc); |
| 394 | extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc); | 400 | extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc); |
| 401 | extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc); | ||
| 395 | extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc); | 402 | extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc); |
| 396 | extern void handle_nested_irq(unsigned int irq); | 403 | extern void handle_nested_irq(unsigned int irq); |
| 397 | 404 | ||
| @@ -420,6 +427,8 @@ static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *c | |||
| 420 | irq_set_chip_and_handler_name(irq, chip, handle, NULL); | 427 | irq_set_chip_and_handler_name(irq, chip, handle, NULL); |
| 421 | } | 428 | } |
| 422 | 429 | ||
| 430 | extern int irq_set_percpu_devid(unsigned int irq); | ||
| 431 | |||
| 423 | extern void | 432 | extern void |
| 424 | __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, |
| 425 | const char *name); | 434 | const char *name); |
| @@ -481,6 +490,13 @@ static inline void irq_set_nested_thread(unsigned int irq, bool nest) | |||
| 481 | irq_clear_status_flags(irq, IRQ_NESTED_THREAD); | 490 | irq_clear_status_flags(irq, IRQ_NESTED_THREAD); |
| 482 | } | 491 | } |
| 483 | 492 | ||
| 493 | static 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 | |||
| 484 | /* Handle dynamic irq creation and destruction */ | 500 | /* Handle dynamic irq creation and destruction */ |
| 485 | extern unsigned int create_irq_nr(unsigned int irq_want, int node); | 501 | extern unsigned int create_irq_nr(unsigned int irq_want, int node); |
| 486 | extern int create_irq(void); | 502 | extern 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 @@ | |||
| 26 | int irq_set_chip(unsigned int irq, struct irq_chip *chip) | 26 | int 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); | |||
| 54 | int irq_set_irq_type(unsigned int irq, unsigned int type) | 54 | int 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); | |||
| 78 | int irq_set_handler_data(unsigned int irq, void *data) | 78 | int 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); | |||
| 98 | int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) | 98 | int 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) | |||
| 119 | int irq_set_chip_data(unsigned int irq, void *data) | 119 | int 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 | ||
| 207 | void 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 | |||
| 216 | void 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 | |||
| 207 | static inline void mask_ack_irq(struct irq_desc *desc) | 225 | static 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 | */ | ||
| 577 | void 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 | |||
| 547 | void | 597 | void |
| 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, | |||
| 593 | void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) | 643 | void 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); | |||
| 71 | extern void irq_shutdown(struct irq_desc *desc); | 71 | extern void irq_shutdown(struct irq_desc *desc); |
| 72 | extern void irq_enable(struct irq_desc *desc); | 72 | extern void irq_enable(struct irq_desc *desc); |
| 73 | extern void irq_disable(struct irq_desc *desc); | 73 | extern void irq_disable(struct irq_desc *desc); |
| 74 | extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu); | ||
| 75 | extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu); | ||
| 74 | extern void mask_irq(struct irq_desc *desc); | 76 | extern void mask_irq(struct irq_desc *desc); |
| 75 | extern void unmask_irq(struct irq_desc *desc); | 77 | extern 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 | |||
| 117 | struct irq_desc * | 125 | struct 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); | ||
| 119 | void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus); | 128 | void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus); |
| 120 | 129 | ||
| 121 | static inline struct irq_desc * | 130 | static inline struct irq_desc * |
| 122 | irq_get_desc_buslock(unsigned int irq, unsigned long *flags) | 131 | irq_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 | ||
| 127 | static inline void | 136 | static inline void |
| @@ -131,9 +140,9 @@ irq_put_desc_busunlock(struct irq_desc *desc, unsigned long flags) | |||
| 131 | } | 140 | } |
| 132 | 141 | ||
| 133 | static inline struct irq_desc * | 142 | static inline struct irq_desc * |
| 134 | irq_get_desc_lock(unsigned int irq, unsigned long *flags) | 143 | irq_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 | ||
| 139 | static inline void | 148 | static 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 | ||
| 426 | struct irq_desc * | 426 | struct 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 | ||
| 457 | int 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 9b956fa20308..67ce837ae52c 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) | |||
| 195 | int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) | 195 | int 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) | |||
| 356 | static int __disable_irq_nosync(unsigned int irq) | 356 | static 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) | |||
| 448 | void enable_irq(unsigned int irq) | 448 | void 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; |
| @@ -467,6 +467,9 @@ static int set_irq_wake_real(unsigned int irq, unsigned int on) | |||
| 467 | struct irq_desc *desc = irq_to_desc(irq); | 467 | struct irq_desc *desc = irq_to_desc(irq); |
| 468 | int ret = -ENXIO; | 468 | int ret = -ENXIO; |
| 469 | 469 | ||
| 470 | if (irq_desc_get_chip(desc)->flags & IRQCHIP_SKIP_SET_WAKE) | ||
| 471 | return 0; | ||
| 472 | |||
| 470 | if (desc->irq_data.chip->irq_set_wake) | 473 | if (desc->irq_data.chip->irq_set_wake) |
| 471 | ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on); | 474 | ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on); |
| 472 | 475 | ||
| @@ -488,7 +491,7 @@ static int set_irq_wake_real(unsigned int irq, unsigned int on) | |||
| 488 | int irq_set_irq_wake(unsigned int irq, unsigned int on) | 491 | int irq_set_irq_wake(unsigned int irq, unsigned int on) |
| 489 | { | 492 | { |
| 490 | unsigned long flags; | 493 | unsigned long flags; |
| 491 | 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); |
| 492 | int ret = 0; | 495 | int ret = 0; |
| 493 | 496 | ||
| 494 | if (!desc) | 497 | if (!desc) |
| @@ -529,7 +532,7 @@ EXPORT_SYMBOL(irq_set_irq_wake); | |||
| 529 | int can_request_irq(unsigned int irq, unsigned long irqflags) | 532 | int can_request_irq(unsigned int irq, unsigned long irqflags) |
| 530 | { | 533 | { |
| 531 | unsigned long flags; | 534 | unsigned long flags; |
| 532 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags); | 535 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
| 533 | int canrequest = 0; | 536 | int canrequest = 0; |
| 534 | 537 | ||
| 535 | if (!desc) | 538 | if (!desc) |
| @@ -1118,6 +1121,8 @@ int setup_irq(unsigned int irq, struct irqaction *act) | |||
| 1118 | int retval; | 1121 | int retval; |
| 1119 | struct irq_desc *desc = irq_to_desc(irq); | 1122 | struct irq_desc *desc = irq_to_desc(irq); |
| 1120 | 1123 | ||
| 1124 | if (WARN_ON(irq_settings_is_per_cpu_devid(desc))) | ||
| 1125 | return -EINVAL; | ||
| 1121 | chip_bus_lock(desc); | 1126 | chip_bus_lock(desc); |
| 1122 | retval = __setup_irq(irq, desc, act); | 1127 | retval = __setup_irq(irq, desc, act); |
| 1123 | chip_bus_sync_unlock(desc); | 1128 | chip_bus_sync_unlock(desc); |
| @@ -1126,7 +1131,7 @@ int setup_irq(unsigned int irq, struct irqaction *act) | |||
| 1126 | } | 1131 | } |
| 1127 | EXPORT_SYMBOL_GPL(setup_irq); | 1132 | EXPORT_SYMBOL_GPL(setup_irq); |
| 1128 | 1133 | ||
| 1129 | /* | 1134 | /* |
| 1130 | * Internal function to unregister an irqaction - used to free | 1135 | * Internal function to unregister an irqaction - used to free |
| 1131 | * regular and special interrupts that are part of the architecture. | 1136 | * regular and special interrupts that are part of the architecture. |
| 1132 | */ | 1137 | */ |
| @@ -1224,7 +1229,10 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) | |||
| 1224 | */ | 1229 | */ |
| 1225 | void remove_irq(unsigned int irq, struct irqaction *act) | 1230 | void remove_irq(unsigned int irq, struct irqaction *act) |
| 1226 | { | 1231 | { |
| 1227 | __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); | ||
| 1228 | } | 1236 | } |
| 1229 | EXPORT_SYMBOL_GPL(remove_irq); | 1237 | EXPORT_SYMBOL_GPL(remove_irq); |
| 1230 | 1238 | ||
| @@ -1246,7 +1254,7 @@ void free_irq(unsigned int irq, void *dev_id) | |||
| 1246 | { | 1254 | { |
| 1247 | struct irq_desc *desc = irq_to_desc(irq); | 1255 | struct irq_desc *desc = irq_to_desc(irq); |
| 1248 | 1256 | ||
| 1249 | if (!desc) | 1257 | if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc))) |
| 1250 | return; | 1258 | return; |
| 1251 | 1259 | ||
| 1252 | #ifdef CONFIG_SMP | 1260 | #ifdef CONFIG_SMP |
| @@ -1324,7 +1332,8 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, | |||
| 1324 | if (!desc) | 1332 | if (!desc) |
| 1325 | return -EINVAL; | 1333 | return -EINVAL; |
| 1326 | 1334 | ||
| 1327 | if (!irq_settings_can_request(desc)) | 1335 | if (!irq_settings_can_request(desc) || |
| 1336 | WARN_ON(irq_settings_is_per_cpu_devid(desc))) | ||
| 1328 | return -EINVAL; | 1337 | return -EINVAL; |
| 1329 | 1338 | ||
| 1330 | if (!handler) { | 1339 | if (!handler) { |
| @@ -1409,3 +1418,194 @@ int request_any_context_irq(unsigned int irq, irq_handler_t handler, | |||
| 1409 | return !ret ? IRQC_IS_HARDIRQ : ret; | 1418 | return !ret ? IRQC_IS_HARDIRQ : ret; |
| 1410 | } | 1419 | } |
| 1411 | EXPORT_SYMBOL_GPL(request_any_context_irq); | 1420 | EXPORT_SYMBOL_GPL(request_any_context_irq); |
| 1421 | |||
| 1422 | void enable_percpu_irq(unsigned int irq, unsigned int type) | ||
| 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 | type &= IRQ_TYPE_SENSE_MASK; | ||
| 1432 | if (type != IRQ_TYPE_NONE) { | ||
| 1433 | int ret; | ||
| 1434 | |||
| 1435 | ret = __irq_set_trigger(desc, irq, type); | ||
| 1436 | |||
| 1437 | if (ret) { | ||
| 1438 | WARN(1, "failed to set type for IRQ%d\n", irq); | ||
| 1439 | goto out; | ||
| 1440 | } | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | irq_percpu_enable(desc, cpu); | ||
| 1444 | out: | ||
| 1445 | irq_put_desc_unlock(desc, flags); | ||
| 1446 | } | ||
| 1447 | |||
| 1448 | void disable_percpu_irq(unsigned int irq) | ||
| 1449 | { | ||
| 1450 | unsigned int cpu = smp_processor_id(); | ||
| 1451 | unsigned long flags; | ||
| 1452 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU); | ||
| 1453 | |||
| 1454 | if (!desc) | ||
| 1455 | return; | ||
| 1456 | |||
| 1457 | irq_percpu_disable(desc, cpu); | ||
| 1458 | irq_put_desc_unlock(desc, flags); | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | /* | ||
| 1462 | * Internal function to unregister a percpu irqaction. | ||
| 1463 | */ | ||
| 1464 | static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_id) | ||
| 1465 | { | ||
| 1466 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 1467 | struct irqaction *action; | ||
| 1468 | unsigned long flags; | ||
| 1469 | |||
| 1470 | WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); | ||
| 1471 | |||
| 1472 | if (!desc) | ||
| 1473 | return NULL; | ||
| 1474 | |||
| 1475 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
| 1476 | |||
| 1477 | action = desc->action; | ||
| 1478 | if (!action || action->percpu_dev_id != dev_id) { | ||
| 1479 | WARN(1, "Trying to free already-free IRQ %d\n", irq); | ||
| 1480 | goto bad; | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | if (!cpumask_empty(desc->percpu_enabled)) { | ||
| 1484 | WARN(1, "percpu IRQ %d still enabled on CPU%d!\n", | ||
| 1485 | irq, cpumask_first(desc->percpu_enabled)); | ||
| 1486 | goto bad; | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | /* Found it - now remove it from the list of entries: */ | ||
| 1490 | desc->action = NULL; | ||
| 1491 | |||
| 1492 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 1493 | |||
| 1494 | unregister_handler_proc(irq, action); | ||
| 1495 | |||
| 1496 | module_put(desc->owner); | ||
| 1497 | return action; | ||
| 1498 | |||
| 1499 | bad: | ||
| 1500 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 1501 | return NULL; | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | /** | ||
| 1505 | * remove_percpu_irq - free a per-cpu interrupt | ||
| 1506 | * @irq: Interrupt line to free | ||
| 1507 | * @act: irqaction for the interrupt | ||
| 1508 | * | ||
| 1509 | * Used to remove interrupts statically setup by the early boot process. | ||
| 1510 | */ | ||
| 1511 | void remove_percpu_irq(unsigned int irq, struct irqaction *act) | ||
| 1512 | { | ||
| 1513 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 1514 | |||
| 1515 | if (desc && irq_settings_is_per_cpu_devid(desc)) | ||
| 1516 | __free_percpu_irq(irq, act->percpu_dev_id); | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | /** | ||
| 1520 | * free_percpu_irq - free an interrupt allocated with request_percpu_irq | ||
| 1521 | * @irq: Interrupt line to free | ||
| 1522 | * @dev_id: Device identity to free | ||
| 1523 | * | ||
| 1524 | * Remove a percpu interrupt handler. The handler is removed, but | ||
| 1525 | * the interrupt line is not disabled. This must be done on each | ||
| 1526 | * CPU before calling this function. The function does not return | ||
| 1527 | * until any executing interrupts for this IRQ have completed. | ||
| 1528 | * | ||
| 1529 | * This function must not be called from interrupt context. | ||
| 1530 | */ | ||
| 1531 | void free_percpu_irq(unsigned int irq, void __percpu *dev_id) | ||
| 1532 | { | ||
| 1533 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 1534 | |||
| 1535 | if (!desc || !irq_settings_is_per_cpu_devid(desc)) | ||
| 1536 | return; | ||
| 1537 | |||
| 1538 | chip_bus_lock(desc); | ||
| 1539 | kfree(__free_percpu_irq(irq, dev_id)); | ||
| 1540 | chip_bus_sync_unlock(desc); | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | /** | ||
| 1544 | * setup_percpu_irq - setup a per-cpu interrupt | ||
| 1545 | * @irq: Interrupt line to setup | ||
| 1546 | * @act: irqaction for the interrupt | ||
| 1547 | * | ||
| 1548 | * Used to statically setup per-cpu interrupts in the early boot process. | ||
| 1549 | */ | ||
| 1550 | int setup_percpu_irq(unsigned int irq, struct irqaction *act) | ||
| 1551 | { | ||
| 1552 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 1553 | int retval; | ||
| 1554 | |||
| 1555 | if (!desc || !irq_settings_is_per_cpu_devid(desc)) | ||
| 1556 | return -EINVAL; | ||
| 1557 | chip_bus_lock(desc); | ||
| 1558 | retval = __setup_irq(irq, desc, act); | ||
| 1559 | chip_bus_sync_unlock(desc); | ||
| 1560 | |||
| 1561 | return retval; | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | /** | ||
| 1565 | * request_percpu_irq - allocate a percpu interrupt line | ||
| 1566 | * @irq: Interrupt line to allocate | ||
| 1567 | * @handler: Function to be called when the IRQ occurs. | ||
| 1568 | * @devname: An ascii name for the claiming device | ||
| 1569 | * @dev_id: A percpu cookie passed back to the handler function | ||
| 1570 | * | ||
| 1571 | * This call allocates interrupt resources, but doesn't | ||
| 1572 | * automatically enable the interrupt. It has to be done on each | ||
| 1573 | * CPU using enable_percpu_irq(). | ||
| 1574 | * | ||
| 1575 | * Dev_id must be globally unique. It is a per-cpu variable, and | ||
| 1576 | * the handler gets called with the interrupted CPU's instance of | ||
| 1577 | * that variable. | ||
| 1578 | */ | ||
| 1579 | int request_percpu_irq(unsigned int irq, irq_handler_t handler, | ||
| 1580 | const char *devname, void __percpu *dev_id) | ||
| 1581 | { | ||
| 1582 | struct irqaction *action; | ||
| 1583 | struct irq_desc *desc; | ||
| 1584 | int retval; | ||
| 1585 | |||
| 1586 | if (!dev_id) | ||
| 1587 | return -EINVAL; | ||
| 1588 | |||
| 1589 | desc = irq_to_desc(irq); | ||
| 1590 | if (!desc || !irq_settings_can_request(desc) || | ||
| 1591 | !irq_settings_is_per_cpu_devid(desc)) | ||
| 1592 | return -EINVAL; | ||
| 1593 | |||
| 1594 | action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); | ||
| 1595 | if (!action) | ||
| 1596 | return -ENOMEM; | ||
| 1597 | |||
| 1598 | action->handler = handler; | ||
| 1599 | action->flags = IRQF_PERCPU; | ||
| 1600 | action->name = devname; | ||
| 1601 | action->percpu_dev_id = dev_id; | ||
| 1602 | |||
| 1603 | chip_bus_lock(desc); | ||
| 1604 | retval = __setup_irq(irq, desc, action); | ||
| 1605 | chip_bus_sync_unlock(desc); | ||
| 1606 | |||
| 1607 | if (retval) | ||
| 1608 | kfree(action); | ||
| 1609 | |||
| 1610 | return retval; | ||
| 1611 | } | ||
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index f76fc00c9877..15e53b1766a6 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <linux/irq.h> | 9 | #include <linux/irq.h> |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
| 12 | #include <linux/syscore_ops.h> | ||
| 12 | 13 | ||
| 13 | #include "internals.h" | 14 | #include "internals.h" |
| 14 | 15 | ||
| @@ -39,25 +40,58 @@ void suspend_device_irqs(void) | |||
| 39 | } | 40 | } |
| 40 | EXPORT_SYMBOL_GPL(suspend_device_irqs); | 41 | EXPORT_SYMBOL_GPL(suspend_device_irqs); |
| 41 | 42 | ||
| 42 | /** | 43 | static void resume_irqs(bool want_early) |
| 43 | * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs() | ||
| 44 | * | ||
| 45 | * Enable all interrupt lines previously disabled by suspend_device_irqs() that | ||
| 46 | * have the IRQS_SUSPENDED flag set. | ||
| 47 | */ | ||
| 48 | void resume_device_irqs(void) | ||
| 49 | { | 44 | { |
| 50 | struct irq_desc *desc; | 45 | struct irq_desc *desc; |
| 51 | int irq; | 46 | int irq; |
| 52 | 47 | ||
| 53 | for_each_irq_desc(irq, desc) { | 48 | for_each_irq_desc(irq, desc) { |
| 54 | unsigned long flags; | 49 | unsigned long flags; |
| 50 | bool is_early = desc->action && | ||
| 51 | desc->action->flags & IRQF_EARLY_RESUME; | ||
| 52 | |||
| 53 | if (is_early != want_early) | ||
| 54 | continue; | ||
| 55 | 55 | ||
| 56 | raw_spin_lock_irqsave(&desc->lock, flags); | 56 | raw_spin_lock_irqsave(&desc->lock, flags); |
| 57 | __enable_irq(desc, irq, true); | 57 | __enable_irq(desc, irq, true); |
| 58 | raw_spin_unlock_irqrestore(&desc->lock, flags); | 58 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | |||
| 62 | /** | ||
| 63 | * irq_pm_syscore_ops - enable interrupt lines early | ||
| 64 | * | ||
| 65 | * Enable all interrupt lines with %IRQF_EARLY_RESUME set. | ||
| 66 | */ | ||
| 67 | static void irq_pm_syscore_resume(void) | ||
| 68 | { | ||
| 69 | resume_irqs(true); | ||
| 70 | } | ||
| 71 | |||
| 72 | static struct syscore_ops irq_pm_syscore_ops = { | ||
| 73 | .resume = irq_pm_syscore_resume, | ||
| 74 | }; | ||
| 75 | |||
| 76 | static int __init irq_pm_init_ops(void) | ||
| 77 | { | ||
| 78 | register_syscore_ops(&irq_pm_syscore_ops); | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | device_initcall(irq_pm_init_ops); | ||
| 83 | |||
| 84 | /** | ||
| 85 | * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs() | ||
| 86 | * | ||
| 87 | * Enable all non-%IRQF_EARLY_RESUME interrupt lines previously | ||
| 88 | * disabled by suspend_device_irqs() that have the IRQS_SUSPENDED flag | ||
| 89 | * set as well as those with %IRQF_FORCE_RESUME. | ||
| 90 | */ | ||
| 91 | void resume_device_irqs(void) | ||
| 92 | { | ||
| 93 | resume_irqs(false); | ||
| 94 | } | ||
| 61 | EXPORT_SYMBOL_GPL(resume_device_irqs); | 95 | EXPORT_SYMBOL_GPL(resume_device_irqs); |
| 62 | 96 | ||
| 63 | /** | 97 | /** |
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 | ||
| 44 | static 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 | |||
| 42 | static inline void irq_settings_set_per_cpu(struct irq_desc *desc) | 49 | static 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; |
