diff options
Diffstat (limited to 'kernel/irq')
| -rw-r--r-- | kernel/irq/Kconfig | 4 | ||||
| -rw-r--r-- | kernel/irq/Makefile | 1 | ||||
| -rw-r--r-- | kernel/irq/chip.c | 3 | ||||
| -rw-r--r-- | kernel/irq/debug.h | 1 | ||||
| -rw-r--r-- | kernel/irq/generic-chip.c | 354 | ||||
| -rw-r--r-- | kernel/irq/irqdesc.c | 22 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 3 | ||||
| -rw-r--r-- | kernel/irq/settings.h | 17 |
8 files changed, 401 insertions, 4 deletions
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index c574f9a12c48..d1d051b38e0b 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig | |||
| @@ -48,6 +48,10 @@ config IRQ_PREFLOW_FASTEOI | |||
| 48 | config IRQ_EDGE_EOI_HANDLER | 48 | config IRQ_EDGE_EOI_HANDLER |
| 49 | bool | 49 | bool |
| 50 | 50 | ||
| 51 | # Generic configurable interrupt chip implementation | ||
| 52 | config GENERIC_IRQ_CHIP | ||
| 53 | bool | ||
| 54 | |||
| 51 | # Support forced irq threading | 55 | # Support forced irq threading |
| 52 | config IRQ_FORCED_THREADING | 56 | config IRQ_FORCED_THREADING |
| 53 | bool | 57 | bool |
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 54329cd7b3ee..73290056cfb6 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | 1 | ||
| 2 | obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o | 2 | obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o |
| 3 | obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o | ||
| 3 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o | 4 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o |
| 4 | obj-$(CONFIG_PROC_FS) += proc.o | 5 | obj-$(CONFIG_PROC_FS) += proc.o |
| 5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o | 6 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 4af1e2b244cb..d5a3009da71a 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -310,6 +310,7 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) | |||
| 310 | out_unlock: | 310 | out_unlock: |
| 311 | raw_spin_unlock(&desc->lock); | 311 | raw_spin_unlock(&desc->lock); |
| 312 | } | 312 | } |
| 313 | EXPORT_SYMBOL_GPL(handle_simple_irq); | ||
| 313 | 314 | ||
| 314 | /** | 315 | /** |
| 315 | * handle_level_irq - Level type irq handler | 316 | * handle_level_irq - Level type irq handler |
| @@ -573,6 +574,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
| 573 | if (handle != handle_bad_irq && is_chained) { | 574 | if (handle != handle_bad_irq && is_chained) { |
| 574 | irq_settings_set_noprobe(desc); | 575 | irq_settings_set_noprobe(desc); |
| 575 | irq_settings_set_norequest(desc); | 576 | irq_settings_set_norequest(desc); |
| 577 | irq_settings_set_nothread(desc); | ||
| 576 | irq_startup(desc); | 578 | irq_startup(desc); |
| 577 | } | 579 | } |
| 578 | out: | 580 | out: |
| @@ -612,6 +614,7 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) | |||
| 612 | 614 | ||
| 613 | irq_put_desc_unlock(desc, flags); | 615 | irq_put_desc_unlock(desc, flags); |
| 614 | } | 616 | } |
| 617 | EXPORT_SYMBOL_GPL(irq_modify_status); | ||
| 615 | 618 | ||
| 616 | /** | 619 | /** |
| 617 | * irq_cpu_online - Invoke all irq_cpu_online functions. | 620 | * irq_cpu_online - Invoke all irq_cpu_online functions. |
diff --git a/kernel/irq/debug.h b/kernel/irq/debug.h index 306cba37e9a5..97a8bfadc88a 100644 --- a/kernel/irq/debug.h +++ b/kernel/irq/debug.h | |||
| @@ -27,6 +27,7 @@ static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc) | |||
| 27 | P(IRQ_PER_CPU); | 27 | P(IRQ_PER_CPU); |
| 28 | P(IRQ_NOPROBE); | 28 | P(IRQ_NOPROBE); |
| 29 | P(IRQ_NOREQUEST); | 29 | P(IRQ_NOREQUEST); |
| 30 | P(IRQ_NOTHREAD); | ||
| 30 | P(IRQ_NOAUTOEN); | 31 | P(IRQ_NOAUTOEN); |
| 31 | 32 | ||
| 32 | PS(IRQS_AUTODETECT); | 33 | PS(IRQS_AUTODETECT); |
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c new file mode 100644 index 000000000000..31a9db711906 --- /dev/null +++ b/kernel/irq/generic-chip.c | |||
| @@ -0,0 +1,354 @@ | |||
| 1 | /* | ||
| 2 | * Library implementing the most common irq chip callback functions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011, Thomas Gleixner | ||
| 5 | */ | ||
| 6 | #include <linux/io.h> | ||
| 7 | #include <linux/irq.h> | ||
| 8 | #include <linux/slab.h> | ||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/kernel_stat.h> | ||
| 11 | #include <linux/syscore_ops.h> | ||
| 12 | |||
| 13 | #include "internals.h" | ||
| 14 | |||
| 15 | static LIST_HEAD(gc_list); | ||
| 16 | static DEFINE_RAW_SPINLOCK(gc_lock); | ||
| 17 | |||
| 18 | static inline struct irq_chip_regs *cur_regs(struct irq_data *d) | ||
| 19 | { | ||
| 20 | return &container_of(d->chip, struct irq_chip_type, chip)->regs; | ||
| 21 | } | ||
| 22 | |||
| 23 | /** | ||
| 24 | * irq_gc_noop - NOOP function | ||
| 25 | * @d: irq_data | ||
| 26 | */ | ||
| 27 | void irq_gc_noop(struct irq_data *d) | ||
| 28 | { | ||
| 29 | } | ||
| 30 | |||
| 31 | /** | ||
| 32 | * irq_gc_mask_disable_reg - Mask chip via disable register | ||
| 33 | * @d: irq_data | ||
| 34 | * | ||
| 35 | * Chip has separate enable/disable registers instead of a single mask | ||
| 36 | * register. | ||
| 37 | */ | ||
| 38 | void irq_gc_mask_disable_reg(struct irq_data *d) | ||
| 39 | { | ||
| 40 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
| 41 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
| 42 | |||
| 43 | irq_gc_lock(gc); | ||
| 44 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->disable); | ||
| 45 | gc->mask_cache &= ~mask; | ||
| 46 | irq_gc_unlock(gc); | ||
| 47 | } | ||
| 48 | |||
| 49 | /** | ||
| 50 | * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register | ||
| 51 | * @d: irq_data | ||
| 52 | * | ||
| 53 | * Chip has a single mask register. Values of this register are cached | ||
| 54 | * and protected by gc->lock | ||
| 55 | */ | ||
| 56 | void irq_gc_mask_set_bit(struct irq_data *d) | ||
| 57 | { | ||
| 58 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
| 59 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
| 60 | |||
| 61 | irq_gc_lock(gc); | ||
| 62 | gc->mask_cache |= mask; | ||
| 63 | irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask); | ||
| 64 | irq_gc_unlock(gc); | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register | ||
| 69 | * @d: irq_data | ||
| 70 | * | ||
| 71 | * Chip has a single mask register. Values of this register are cached | ||
| 72 | * and protected by gc->lock | ||
| 73 | */ | ||
| 74 | void irq_gc_mask_clr_bit(struct irq_data *d) | ||
| 75 | { | ||
| 76 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
| 77 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
| 78 | |||
| 79 | irq_gc_lock(gc); | ||
| 80 | gc->mask_cache &= ~mask; | ||
| 81 | irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask); | ||
| 82 | irq_gc_unlock(gc); | ||
| 83 | } | ||
| 84 | |||
| 85 | /** | ||
| 86 | * irq_gc_unmask_enable_reg - Unmask chip via enable register | ||
| 87 | * @d: irq_data | ||
| 88 | * | ||
| 89 | * Chip has separate enable/disable registers instead of a single mask | ||
| 90 | * register. | ||
| 91 | */ | ||
| 92 | void irq_gc_unmask_enable_reg(struct irq_data *d) | ||
| 93 | { | ||
| 94 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
| 95 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
| 96 | |||
| 97 | irq_gc_lock(gc); | ||
| 98 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->enable); | ||
| 99 | gc->mask_cache |= mask; | ||
| 100 | irq_gc_unlock(gc); | ||
| 101 | } | ||
| 102 | |||
| 103 | /** | ||
| 104 | * irq_gc_ack - Ack pending interrupt | ||
| 105 | * @d: irq_data | ||
| 106 | */ | ||
| 107 | void irq_gc_ack(struct irq_data *d) | ||
| 108 | { | ||
| 109 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
| 110 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
| 111 | |||
| 112 | irq_gc_lock(gc); | ||
| 113 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); | ||
| 114 | irq_gc_unlock(gc); | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * irq_gc_mask_disable_reg_and_ack- Mask and ack pending interrupt | ||
| 119 | * @d: irq_data | ||
| 120 | */ | ||
| 121 | void irq_gc_mask_disable_reg_and_ack(struct irq_data *d) | ||
| 122 | { | ||
| 123 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
| 124 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
| 125 | |||
| 126 | irq_gc_lock(gc); | ||
| 127 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->mask); | ||
| 128 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); | ||
| 129 | irq_gc_unlock(gc); | ||
| 130 | } | ||
| 131 | |||
| 132 | /** | ||
| 133 | * irq_gc_eoi - EOI interrupt | ||
| 134 | * @d: irq_data | ||
| 135 | */ | ||
| 136 | void irq_gc_eoi(struct irq_data *d) | ||
| 137 | { | ||
| 138 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
| 139 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
| 140 | |||
| 141 | irq_gc_lock(gc); | ||
| 142 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->eoi); | ||
| 143 | irq_gc_unlock(gc); | ||
| 144 | } | ||
| 145 | |||
| 146 | /** | ||
| 147 | * irq_gc_set_wake - Set/clr wake bit for an interrupt | ||
| 148 | * @d: irq_data | ||
| 149 | * | ||
| 150 | * For chips where the wake from suspend functionality is not | ||
| 151 | * configured in a separate register and the wakeup active state is | ||
| 152 | * just stored in a bitmask. | ||
| 153 | */ | ||
| 154 | int irq_gc_set_wake(struct irq_data *d, unsigned int on) | ||
| 155 | { | ||
| 156 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
| 157 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
| 158 | |||
| 159 | if (!(mask & gc->wake_enabled)) | ||
| 160 | return -EINVAL; | ||
| 161 | |||
| 162 | irq_gc_lock(gc); | ||
| 163 | if (on) | ||
| 164 | gc->wake_active |= mask; | ||
| 165 | else | ||
| 166 | gc->wake_active &= ~mask; | ||
| 167 | irq_gc_unlock(gc); | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | /** | ||
| 172 | * irq_alloc_generic_chip - Allocate a generic chip and initialize it | ||
| 173 | * @name: Name of the irq chip | ||
| 174 | * @num_ct: Number of irq_chip_type instances associated with this | ||
| 175 | * @irq_base: Interrupt base nr for this chip | ||
| 176 | * @reg_base: Register base address (virtual) | ||
| 177 | * @handler: Default flow handler associated with this chip | ||
| 178 | * | ||
| 179 | * Returns an initialized irq_chip_generic structure. The chip defaults | ||
| 180 | * to the primary (index 0) irq_chip_type and @handler | ||
| 181 | */ | ||
| 182 | struct irq_chip_generic * | ||
| 183 | irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base, | ||
| 184 | void __iomem *reg_base, irq_flow_handler_t handler) | ||
| 185 | { | ||
| 186 | struct irq_chip_generic *gc; | ||
| 187 | unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); | ||
| 188 | |||
| 189 | gc = kzalloc(sz, GFP_KERNEL); | ||
| 190 | if (gc) { | ||
| 191 | raw_spin_lock_init(&gc->lock); | ||
| 192 | gc->num_ct = num_ct; | ||
| 193 | gc->irq_base = irq_base; | ||
| 194 | gc->reg_base = reg_base; | ||
| 195 | gc->chip_types->chip.name = name; | ||
| 196 | gc->chip_types->handler = handler; | ||
| 197 | } | ||
| 198 | return gc; | ||
| 199 | } | ||
| 200 | |||
| 201 | /* | ||
| 202 | * Separate lockdep class for interrupt chip which can nest irq_desc | ||
| 203 | * lock. | ||
| 204 | */ | ||
| 205 | static struct lock_class_key irq_nested_lock_class; | ||
| 206 | |||
| 207 | /** | ||
| 208 | * irq_setup_generic_chip - Setup a range of interrupts with a generic chip | ||
| 209 | * @gc: Generic irq chip holding all data | ||
| 210 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | ||
| 211 | * @flags: Flags for initialization | ||
| 212 | * @clr: IRQ_* bits to clear | ||
| 213 | * @set: IRQ_* bits to set | ||
| 214 | * | ||
| 215 | * Set up max. 32 interrupts starting from gc->irq_base. Note, this | ||
| 216 | * initializes all interrupts to the primary irq_chip_type and its | ||
| 217 | * associated handler. | ||
| 218 | */ | ||
| 219 | void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, | ||
| 220 | enum irq_gc_flags flags, unsigned int clr, | ||
| 221 | unsigned int set) | ||
| 222 | { | ||
| 223 | struct irq_chip_type *ct = gc->chip_types; | ||
| 224 | unsigned int i; | ||
| 225 | |||
| 226 | raw_spin_lock(&gc_lock); | ||
| 227 | list_add_tail(&gc->list, &gc_list); | ||
| 228 | raw_spin_unlock(&gc_lock); | ||
| 229 | |||
| 230 | /* Init mask cache ? */ | ||
| 231 | if (flags & IRQ_GC_INIT_MASK_CACHE) | ||
| 232 | gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); | ||
| 233 | |||
| 234 | for (i = gc->irq_base; msk; msk >>= 1, i++) { | ||
| 235 | if (!msk & 0x01) | ||
| 236 | continue; | ||
| 237 | |||
| 238 | if (flags & IRQ_GC_INIT_NESTED_LOCK) | ||
| 239 | irq_set_lockdep_class(i, &irq_nested_lock_class); | ||
| 240 | |||
| 241 | irq_set_chip_and_handler(i, &ct->chip, ct->handler); | ||
| 242 | irq_set_chip_data(i, gc); | ||
| 243 | irq_modify_status(i, clr, set); | ||
| 244 | } | ||
| 245 | gc->irq_cnt = i - gc->irq_base; | ||
| 246 | } | ||
| 247 | |||
| 248 | /** | ||
| 249 | * irq_setup_alt_chip - Switch to alternative chip | ||
| 250 | * @d: irq_data for this interrupt | ||
| 251 | * @type Flow type to be initialized | ||
| 252 | * | ||
| 253 | * Only to be called from chip->irq_set_type() callbacks. | ||
| 254 | */ | ||
| 255 | int irq_setup_alt_chip(struct irq_data *d, unsigned int type) | ||
| 256 | { | ||
| 257 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
| 258 | struct irq_chip_type *ct = gc->chip_types; | ||
| 259 | unsigned int i; | ||
| 260 | |||
| 261 | for (i = 0; i < gc->num_ct; i++, ct++) { | ||
| 262 | if (ct->type & type) { | ||
| 263 | d->chip = &ct->chip; | ||
| 264 | irq_data_to_desc(d)->handle_irq = ct->handler; | ||
| 265 | return 0; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | return -EINVAL; | ||
| 269 | } | ||
| 270 | |||
| 271 | /** | ||
| 272 | * irq_remove_generic_chip - Remove a chip | ||
| 273 | * @gc: Generic irq chip holding all data | ||
| 274 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | ||
| 275 | * @clr: IRQ_* bits to clear | ||
| 276 | * @set: IRQ_* bits to set | ||
| 277 | * | ||
| 278 | * Remove up to 32 interrupts starting from gc->irq_base. | ||
| 279 | */ | ||
| 280 | void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, | ||
| 281 | unsigned int clr, unsigned int set) | ||
| 282 | { | ||
| 283 | unsigned int i = gc->irq_base; | ||
| 284 | |||
| 285 | raw_spin_lock(&gc_lock); | ||
| 286 | list_del(&gc->list); | ||
| 287 | raw_spin_unlock(&gc_lock); | ||
| 288 | |||
| 289 | for (; msk; msk >>= 1, i++) { | ||
| 290 | if (!msk & 0x01) | ||
| 291 | continue; | ||
| 292 | |||
| 293 | /* Remove handler first. That will mask the irq line */ | ||
| 294 | irq_set_handler(i, NULL); | ||
| 295 | irq_set_chip(i, &no_irq_chip); | ||
| 296 | irq_set_chip_data(i, NULL); | ||
| 297 | irq_modify_status(i, clr, set); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | #ifdef CONFIG_PM | ||
| 302 | static int irq_gc_suspend(void) | ||
| 303 | { | ||
| 304 | struct irq_chip_generic *gc; | ||
| 305 | |||
| 306 | list_for_each_entry(gc, &gc_list, list) { | ||
| 307 | struct irq_chip_type *ct = gc->chip_types; | ||
| 308 | |||
| 309 | if (ct->chip.irq_suspend) | ||
| 310 | ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base)); | ||
| 311 | } | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | static void irq_gc_resume(void) | ||
| 316 | { | ||
| 317 | struct irq_chip_generic *gc; | ||
| 318 | |||
| 319 | list_for_each_entry(gc, &gc_list, list) { | ||
| 320 | struct irq_chip_type *ct = gc->chip_types; | ||
| 321 | |||
| 322 | if (ct->chip.irq_resume) | ||
| 323 | ct->chip.irq_resume(irq_get_irq_data(gc->irq_base)); | ||
| 324 | } | ||
| 325 | } | ||
| 326 | #else | ||
| 327 | #define irq_gc_suspend NULL | ||
| 328 | #define irq_gc_resume NULL | ||
| 329 | #endif | ||
| 330 | |||
| 331 | static void irq_gc_shutdown(void) | ||
| 332 | { | ||
| 333 | struct irq_chip_generic *gc; | ||
| 334 | |||
| 335 | list_for_each_entry(gc, &gc_list, list) { | ||
| 336 | struct irq_chip_type *ct = gc->chip_types; | ||
| 337 | |||
| 338 | if (ct->chip.irq_pm_shutdown) | ||
| 339 | ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base)); | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | static struct syscore_ops irq_gc_syscore_ops = { | ||
| 344 | .suspend = irq_gc_suspend, | ||
| 345 | .resume = irq_gc_resume, | ||
| 346 | .shutdown = irq_gc_shutdown, | ||
| 347 | }; | ||
| 348 | |||
| 349 | static int __init irq_gc_init_ops(void) | ||
| 350 | { | ||
| 351 | register_syscore_ops(&irq_gc_syscore_ops); | ||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | device_initcall(irq_gc_init_ops); | ||
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 2c039c9b9383..886e80347b32 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c | |||
| @@ -22,7 +22,7 @@ | |||
| 22 | */ | 22 | */ |
| 23 | static struct lock_class_key irq_desc_lock_class; | 23 | static struct lock_class_key irq_desc_lock_class; |
| 24 | 24 | ||
| 25 | #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS) | 25 | #if defined(CONFIG_SMP) |
| 26 | static void __init init_irq_default_affinity(void) | 26 | static void __init init_irq_default_affinity(void) |
| 27 | { | 27 | { |
| 28 | alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT); | 28 | alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT); |
| @@ -290,6 +290,22 @@ static int irq_expand_nr_irqs(unsigned int nr) | |||
| 290 | 290 | ||
| 291 | #endif /* !CONFIG_SPARSE_IRQ */ | 291 | #endif /* !CONFIG_SPARSE_IRQ */ |
| 292 | 292 | ||
| 293 | /** | ||
| 294 | * generic_handle_irq - Invoke the handler for a particular irq | ||
| 295 | * @irq: The irq number to handle | ||
| 296 | * | ||
| 297 | */ | ||
| 298 | int generic_handle_irq(unsigned int irq) | ||
| 299 | { | ||
| 300 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 301 | |||
| 302 | if (!desc) | ||
| 303 | return -EINVAL; | ||
| 304 | generic_handle_irq_desc(irq, desc); | ||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | EXPORT_SYMBOL_GPL(generic_handle_irq); | ||
| 308 | |||
| 293 | /* Dynamic interrupt handling */ | 309 | /* Dynamic interrupt handling */ |
| 294 | 310 | ||
| 295 | /** | 311 | /** |
| @@ -311,6 +327,7 @@ void irq_free_descs(unsigned int from, unsigned int cnt) | |||
| 311 | bitmap_clear(allocated_irqs, from, cnt); | 327 | bitmap_clear(allocated_irqs, from, cnt); |
| 312 | mutex_unlock(&sparse_irq_lock); | 328 | mutex_unlock(&sparse_irq_lock); |
| 313 | } | 329 | } |
| 330 | EXPORT_SYMBOL_GPL(irq_free_descs); | ||
| 314 | 331 | ||
| 315 | /** | 332 | /** |
| 316 | * irq_alloc_descs - allocate and initialize a range of irq descriptors | 333 | * irq_alloc_descs - allocate and initialize a range of irq descriptors |
| @@ -351,6 +368,7 @@ err: | |||
| 351 | mutex_unlock(&sparse_irq_lock); | 368 | mutex_unlock(&sparse_irq_lock); |
| 352 | return ret; | 369 | return ret; |
| 353 | } | 370 | } |
| 371 | EXPORT_SYMBOL_GPL(irq_alloc_descs); | ||
| 354 | 372 | ||
| 355 | /** | 373 | /** |
| 356 | * irq_reserve_irqs - mark irqs allocated | 374 | * irq_reserve_irqs - mark irqs allocated |
| @@ -430,7 +448,6 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) | |||
| 430 | *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; | 448 | *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; |
| 431 | } | 449 | } |
| 432 | 450 | ||
| 433 | #ifdef CONFIG_GENERIC_HARDIRQS | ||
| 434 | unsigned int kstat_irqs(unsigned int irq) | 451 | unsigned int kstat_irqs(unsigned int irq) |
| 435 | { | 452 | { |
| 436 | struct irq_desc *desc = irq_to_desc(irq); | 453 | struct irq_desc *desc = irq_to_desc(irq); |
| @@ -443,4 +460,3 @@ unsigned int kstat_irqs(unsigned int irq) | |||
| 443 | sum += *per_cpu_ptr(desc->kstat_irqs, cpu); | 460 | sum += *per_cpu_ptr(desc->kstat_irqs, cpu); |
| 444 | return sum; | 461 | return sum; |
| 445 | } | 462 | } |
| 446 | #endif /* CONFIG_GENERIC_HARDIRQS */ | ||
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 07c1611f3899..f7ce0021e1c4 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -900,7 +900,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 900 | */ | 900 | */ |
| 901 | new->handler = irq_nested_primary_handler; | 901 | new->handler = irq_nested_primary_handler; |
| 902 | } else { | 902 | } else { |
| 903 | irq_setup_forced_threading(new); | 903 | if (irq_settings_can_thread(desc)) |
| 904 | irq_setup_forced_threading(new); | ||
| 904 | } | 905 | } |
| 905 | 906 | ||
| 906 | /* | 907 | /* |
diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h index 0d91730b6330..f1667833d444 100644 --- a/kernel/irq/settings.h +++ b/kernel/irq/settings.h | |||
| @@ -8,6 +8,7 @@ enum { | |||
| 8 | _IRQ_LEVEL = IRQ_LEVEL, | 8 | _IRQ_LEVEL = IRQ_LEVEL, |
| 9 | _IRQ_NOPROBE = IRQ_NOPROBE, | 9 | _IRQ_NOPROBE = IRQ_NOPROBE, |
| 10 | _IRQ_NOREQUEST = IRQ_NOREQUEST, | 10 | _IRQ_NOREQUEST = IRQ_NOREQUEST, |
| 11 | _IRQ_NOTHREAD = IRQ_NOTHREAD, | ||
| 11 | _IRQ_NOAUTOEN = IRQ_NOAUTOEN, | 12 | _IRQ_NOAUTOEN = IRQ_NOAUTOEN, |
| 12 | _IRQ_MOVE_PCNTXT = IRQ_MOVE_PCNTXT, | 13 | _IRQ_MOVE_PCNTXT = IRQ_MOVE_PCNTXT, |
| 13 | _IRQ_NO_BALANCING = IRQ_NO_BALANCING, | 14 | _IRQ_NO_BALANCING = IRQ_NO_BALANCING, |
| @@ -20,6 +21,7 @@ enum { | |||
| 20 | #define IRQ_LEVEL GOT_YOU_MORON | 21 | #define IRQ_LEVEL GOT_YOU_MORON |
| 21 | #define IRQ_NOPROBE GOT_YOU_MORON | 22 | #define IRQ_NOPROBE GOT_YOU_MORON |
| 22 | #define IRQ_NOREQUEST GOT_YOU_MORON | 23 | #define IRQ_NOREQUEST GOT_YOU_MORON |
| 24 | #define IRQ_NOTHREAD GOT_YOU_MORON | ||
| 23 | #define IRQ_NOAUTOEN GOT_YOU_MORON | 25 | #define IRQ_NOAUTOEN GOT_YOU_MORON |
| 24 | #define IRQ_NESTED_THREAD GOT_YOU_MORON | 26 | #define IRQ_NESTED_THREAD GOT_YOU_MORON |
| 25 | #undef IRQF_MODIFY_MASK | 27 | #undef IRQF_MODIFY_MASK |
| @@ -94,6 +96,21 @@ static inline void irq_settings_set_norequest(struct irq_desc *desc) | |||
| 94 | desc->status_use_accessors |= _IRQ_NOREQUEST; | 96 | desc->status_use_accessors |= _IRQ_NOREQUEST; |
| 95 | } | 97 | } |
| 96 | 98 | ||
| 99 | static inline bool irq_settings_can_thread(struct irq_desc *desc) | ||
| 100 | { | ||
| 101 | return !(desc->status_use_accessors & _IRQ_NOTHREAD); | ||
| 102 | } | ||
| 103 | |||
| 104 | static inline void irq_settings_clr_nothread(struct irq_desc *desc) | ||
| 105 | { | ||
| 106 | desc->status_use_accessors &= ~_IRQ_NOTHREAD; | ||
| 107 | } | ||
| 108 | |||
| 109 | static inline void irq_settings_set_nothread(struct irq_desc *desc) | ||
| 110 | { | ||
| 111 | desc->status_use_accessors |= _IRQ_NOTHREAD; | ||
| 112 | } | ||
| 113 | |||
| 97 | static inline bool irq_settings_can_probe(struct irq_desc *desc) | 114 | static inline bool irq_settings_can_probe(struct irq_desc *desc) |
| 98 | { | 115 | { |
| 99 | return !(desc->status_use_accessors & _IRQ_NOPROBE); | 116 | return !(desc->status_use_accessors & _IRQ_NOPROBE); |
