Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'irq/threaded' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'irq/threaded' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
genirq: fix devres.o build for GENERIC_HARDIRQS=n
genirq: provide old request_irq() for CONFIG_GENERIC_HARDIRQ=n
genirq: threaded irq handlers review fixups
genirq: add support for threaded interrupts to devres
genirq: add threaded interrupt handler support

+320 -26
+1 -1
include/linux/hardirq.h
··· 116 116 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET 117 117 #endif 118 118 119 - #ifdef CONFIG_SMP 119 + #if defined(CONFIG_SMP) || defined(CONFIG_GENERIC_HARDIRQS) 120 120 extern void synchronize_irq(unsigned int irq); 121 121 #else 122 122 # define synchronize_irq(irq) barrier()
+70 -5
include/linux/interrupt.h
··· 59 59 #define IRQF_NOBALANCING 0x00000800 60 60 #define IRQF_IRQPOLL 0x00001000 61 61 62 + /* 63 + * Bits used by threaded handlers: 64 + * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run 65 + * IRQTF_DIED - handler thread died 66 + * IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed 67 + */ 68 + enum { 69 + IRQTF_RUNTHREAD, 70 + IRQTF_DIED, 71 + IRQTF_WARNED, 72 + }; 73 + 62 74 typedef irqreturn_t (*irq_handler_t)(int, void *); 63 75 64 76 /** ··· 83 71 * @next: pointer to the next irqaction for shared interrupts 84 72 * @irq: interrupt number 85 73 * @dir: pointer to the proc/irq/NN/name entry 74 + * @thread_fn: interupt handler function for threaded interrupts 75 + * @thread: thread pointer for threaded interrupts 76 + * @thread_flags: flags related to @thread 86 77 */ 87 78 struct irqaction { 88 79 irq_handler_t handler; ··· 96 81 struct irqaction *next; 97 82 int irq; 98 83 struct proc_dir_entry *dir; 84 + irq_handler_t thread_fn; 85 + struct task_struct *thread; 86 + unsigned long thread_flags; 99 87 }; 100 88 101 89 extern irqreturn_t no_action(int cpl, void *dev_id); 102 - extern int __must_check request_irq(unsigned int, irq_handler_t handler, 103 - unsigned long, const char *, void *); 90 + 91 + #ifdef CONFIG_GENERIC_HARDIRQS 92 + extern int __must_check 93 + request_threaded_irq(unsigned int irq, irq_handler_t handler, 94 + irq_handler_t thread_fn, 95 + unsigned long flags, const char *name, void *dev); 96 + 97 + static inline int __must_check 98 + request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 99 + const char *name, void *dev) 100 + { 101 + return request_threaded_irq(irq, handler, NULL, flags, name, dev); 102 + } 103 + 104 + extern void exit_irq_thread(void); 105 + #else 106 + 107 + extern int __must_check 108 + request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 109 + const char *name, void *dev); 110 + 111 + /* 112 + * Special function to avoid ifdeffery in kernel/irq/devres.c which 113 + * gets magically built by GENERIC_HARDIRQS=n architectures (sparc, 114 + * m68k). I really love these $@%#!* obvious Makefile references: 115 + * ../../../kernel/irq/devres.o 116 + */ 117 + static inline int __must_check 118 + request_threaded_irq(unsigned int irq, irq_handler_t handler, 119 + irq_handler_t thread_fn, 120 + unsigned long flags, const char *name, void *dev) 121 + { 122 + return request_irq(irq, handler, flags, name, dev); 123 + } 124 + 125 + static inline void exit_irq_thread(void) { } 126 + #endif 127 + 104 128 extern void free_irq(unsigned int, void *); 105 129 106 130 struct device; 107 131 108 - extern int __must_check devm_request_irq(struct device *dev, unsigned int irq, 109 - irq_handler_t handler, unsigned long irqflags, 110 - const char *devname, void *dev_id); 132 + extern int __must_check 133 + devm_request_threaded_irq(struct device *dev, unsigned int irq, 134 + irq_handler_t handler, irq_handler_t thread_fn, 135 + unsigned long irqflags, const char *devname, 136 + void *dev_id); 137 + 138 + static inline int __must_check 139 + devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, 140 + unsigned long irqflags, const char *devname, void *dev_id) 141 + { 142 + return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags, 143 + devname, dev_id); 144 + } 145 + 111 146 extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id); 112 147 113 148 /*
+5
include/linux/irq.h
··· 22 22 #include <linux/irqnr.h> 23 23 #include <linux/errno.h> 24 24 #include <linux/topology.h> 25 + #include <linux/wait.h> 25 26 26 27 #include <asm/irq.h> 27 28 #include <asm/ptrace.h> ··· 159 158 * @affinity: IRQ affinity on SMP 160 159 * @cpu: cpu index useful for balancing 161 160 * @pending_mask: pending rebalanced interrupts 161 + * @threads_active: number of irqaction threads currently running 162 + * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers 162 163 * @dir: /proc/irq/ procfs entry 163 164 * @name: flow handler name for /proc/interrupts output 164 165 */ ··· 192 189 cpumask_var_t pending_mask; 193 190 #endif 194 191 #endif 192 + atomic_t threads_active; 193 + wait_queue_head_t wait_for_threads; 195 194 #ifdef CONFIG_PROC_FS 196 195 struct proc_dir_entry *dir; 197 196 #endif
+2
include/linux/irqreturn.h
··· 5 5 * enum irqreturn 6 6 * @IRQ_NONE interrupt was not from this device 7 7 * @IRQ_HANDLED interrupt was handled by this device 8 + * @IRQ_WAKE_THREAD handler requests to wake the handler thread 8 9 */ 9 10 enum irqreturn { 10 11 IRQ_NONE, 11 12 IRQ_HANDLED, 13 + IRQ_WAKE_THREAD, 12 14 }; 13 15 14 16 typedef enum irqreturn irqreturn_t;
+5
include/linux/sched.h
··· 1294 1294 /* Protection of (de-)allocation: mm, files, fs, tty, keyrings */ 1295 1295 spinlock_t alloc_lock; 1296 1296 1297 + #ifdef CONFIG_GENERIC_HARDIRQS 1298 + /* IRQ handler threads */ 1299 + struct irqaction *irqaction; 1300 + #endif 1301 + 1297 1302 /* Protection of the PI data structures: */ 1298 1303 spinlock_t pi_lock; 1299 1304
+2
kernel/exit.c
··· 923 923 schedule(); 924 924 } 925 925 926 + exit_irq_thread(); 927 + 926 928 exit_signals(tsk); /* sets PF_EXITING */ 927 929 /* 928 930 * tsk->flags are checked in the futex code to protect against
+10 -6
kernel/irq/devres.c
··· 26 26 } 27 27 28 28 /** 29 - * devm_request_irq - allocate an interrupt line for a managed device 29 + * devm_request_threaded_irq - allocate an interrupt line for a managed device 30 30 * @dev: device to request interrupt for 31 31 * @irq: Interrupt line to allocate 32 32 * @handler: Function to be called when the IRQ occurs 33 + * @thread_fn: function to be called in a threaded interrupt context. NULL 34 + * for devices which handle everything in @handler 33 35 * @irqflags: Interrupt type flags 34 36 * @devname: An ascii name for the claiming device 35 37 * @dev_id: A cookie passed back to the handler function ··· 44 42 * If an IRQ allocated with this function needs to be freed 45 43 * separately, dev_free_irq() must be used. 46 44 */ 47 - int devm_request_irq(struct device *dev, unsigned int irq, 48 - irq_handler_t handler, unsigned long irqflags, 49 - const char *devname, void *dev_id) 45 + int devm_request_threaded_irq(struct device *dev, unsigned int irq, 46 + irq_handler_t handler, irq_handler_t thread_fn, 47 + unsigned long irqflags, const char *devname, 48 + void *dev_id) 50 49 { 51 50 struct irq_devres *dr; 52 51 int rc; ··· 57 54 if (!dr) 58 55 return -ENOMEM; 59 56 60 - rc = request_irq(irq, handler, irqflags, devname, dev_id); 57 + rc = request_threaded_irq(irq, handler, thread_fn, irqflags, devname, 58 + dev_id); 61 59 if (rc) { 62 60 devres_free(dr); 63 61 return rc; ··· 70 66 71 67 return 0; 72 68 } 73 - EXPORT_SYMBOL(devm_request_irq); 69 + EXPORT_SYMBOL(devm_request_threaded_irq); 74 70 75 71 /** 76 72 * devm_free_irq - free an interrupt
+49 -1
kernel/irq/handle.c
··· 339 339 return IRQ_NONE; 340 340 } 341 341 342 + static void warn_no_thread(unsigned int irq, struct irqaction *action) 343 + { 344 + if (test_and_set_bit(IRQTF_WARNED, &action->thread_flags)) 345 + return; 346 + 347 + printk(KERN_WARNING "IRQ %d device %s returned IRQ_WAKE_THREAD " 348 + "but no thread function available.", irq, action->name); 349 + } 350 + 342 351 DEFINE_TRACE(irq_handler_entry); 343 352 DEFINE_TRACE(irq_handler_exit); 344 353 ··· 372 363 trace_irq_handler_entry(irq, action); 373 364 ret = action->handler(irq, action->dev_id); 374 365 trace_irq_handler_exit(irq, action, ret); 375 - if (ret == IRQ_HANDLED) 366 + 367 + switch (ret) { 368 + case IRQ_WAKE_THREAD: 369 + /* 370 + * Set result to handled so the spurious check 371 + * does not trigger. 372 + */ 373 + ret = IRQ_HANDLED; 374 + 375 + /* 376 + * Catch drivers which return WAKE_THREAD but 377 + * did not set up a thread function 378 + */ 379 + if (unlikely(!action->thread_fn)) { 380 + warn_no_thread(irq, action); 381 + break; 382 + } 383 + 384 + /* 385 + * Wake up the handler thread for this 386 + * action. In case the thread crashed and was 387 + * killed we just pretend that we handled the 388 + * interrupt. The hardirq handler above has 389 + * disabled the device interrupt, so no irq 390 + * storm is lurking. 391 + */ 392 + if (likely(!test_bit(IRQTF_DIED, 393 + &action->thread_flags))) { 394 + set_bit(IRQTF_RUNTHREAD, &action->thread_flags); 395 + wake_up_process(action->thread); 396 + } 397 + 398 + /* Fall through to add to randomness */ 399 + case IRQ_HANDLED: 376 400 status |= action->flags; 401 + break; 402 + 403 + default: 404 + break; 405 + } 406 + 377 407 retval |= ret; 378 408 action = action->next; 379 409 } while (action);
+176 -13
kernel/irq/manage.c
··· 8 8 */ 9 9 10 10 #include <linux/irq.h> 11 + #include <linux/kthread.h> 11 12 #include <linux/module.h> 12 13 #include <linux/random.h> 13 14 #include <linux/interrupt.h> 14 15 #include <linux/slab.h> 16 + #include <linux/sched.h> 15 17 16 18 #include "internals.h" 17 - 18 - #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS) 19 - cpumask_var_t irq_default_affinity; 20 19 21 20 /** 22 21 * synchronize_irq - wait for pending IRQ handlers (on other CPUs) ··· 52 53 53 54 /* Oops, that failed? */ 54 55 } while (status & IRQ_INPROGRESS); 56 + 57 + /* 58 + * We made sure that no hardirq handler is running. Now verify 59 + * that no threaded handlers are active. 60 + */ 61 + wait_event(desc->wait_for_threads, !atomic_read(&desc->threads_active)); 55 62 } 56 63 EXPORT_SYMBOL(synchronize_irq); 64 + 65 + #ifdef CONFIG_SMP 66 + cpumask_var_t irq_default_affinity; 57 67 58 68 /** 59 69 * irq_can_set_affinity - Check if the affinity of a given irq can be set ··· 78 70 return 0; 79 71 80 72 return 1; 73 + } 74 + 75 + static void 76 + irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask) 77 + { 78 + struct irqaction *action = desc->action; 79 + 80 + while (action) { 81 + if (action->thread) 82 + set_cpus_allowed_ptr(action->thread, cpumask); 83 + action = action->next; 84 + } 81 85 } 82 86 83 87 /** ··· 120 100 cpumask_copy(desc->affinity, cpumask); 121 101 desc->chip->set_affinity(irq, cpumask); 122 102 #endif 103 + irq_set_thread_affinity(desc, cpumask); 123 104 desc->status |= IRQ_AFFINITY_SET; 124 105 spin_unlock_irqrestore(&desc->lock, flags); 125 106 return 0; ··· 171 150 172 151 spin_lock_irqsave(&desc->lock, flags); 173 152 ret = setup_affinity(irq, desc); 153 + if (!ret) 154 + irq_set_thread_affinity(desc, desc->affinity); 174 155 spin_unlock_irqrestore(&desc->lock, flags); 175 156 176 157 return ret; ··· 424 401 return ret; 425 402 } 426 403 404 + static int irq_wait_for_interrupt(struct irqaction *action) 405 + { 406 + while (!kthread_should_stop()) { 407 + set_current_state(TASK_INTERRUPTIBLE); 408 + 409 + if (test_and_clear_bit(IRQTF_RUNTHREAD, 410 + &action->thread_flags)) { 411 + __set_current_state(TASK_RUNNING); 412 + return 0; 413 + } 414 + schedule(); 415 + } 416 + return -1; 417 + } 418 + 419 + /* 420 + * Interrupt handler thread 421 + */ 422 + static int irq_thread(void *data) 423 + { 424 + struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, }; 425 + struct irqaction *action = data; 426 + struct irq_desc *desc = irq_to_desc(action->irq); 427 + int wake; 428 + 429 + sched_setscheduler(current, SCHED_FIFO, &param); 430 + current->irqaction = action; 431 + 432 + while (!irq_wait_for_interrupt(action)) { 433 + 434 + atomic_inc(&desc->threads_active); 435 + 436 + spin_lock_irq(&desc->lock); 437 + if (unlikely(desc->status & IRQ_DISABLED)) { 438 + /* 439 + * CHECKME: We might need a dedicated 440 + * IRQ_THREAD_PENDING flag here, which 441 + * retriggers the thread in check_irq_resend() 442 + * but AFAICT IRQ_PENDING should be fine as it 443 + * retriggers the interrupt itself --- tglx 444 + */ 445 + desc->status |= IRQ_PENDING; 446 + spin_unlock_irq(&desc->lock); 447 + } else { 448 + spin_unlock_irq(&desc->lock); 449 + 450 + action->thread_fn(action->irq, action->dev_id); 451 + } 452 + 453 + wake = atomic_dec_and_test(&desc->threads_active); 454 + 455 + if (wake && waitqueue_active(&desc->wait_for_threads)) 456 + wake_up(&desc->wait_for_threads); 457 + } 458 + 459 + /* 460 + * Clear irqaction. Otherwise exit_irq_thread() would make 461 + * fuzz about an active irq thread going into nirvana. 462 + */ 463 + current->irqaction = NULL; 464 + return 0; 465 + } 466 + 467 + /* 468 + * Called from do_exit() 469 + */ 470 + void exit_irq_thread(void) 471 + { 472 + struct task_struct *tsk = current; 473 + 474 + if (!tsk->irqaction) 475 + return; 476 + 477 + printk(KERN_ERR 478 + "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", 479 + tsk->comm ? tsk->comm : "", tsk->pid, tsk->irqaction->irq); 480 + 481 + /* 482 + * Set the THREAD DIED flag to prevent further wakeups of the 483 + * soon to be gone threaded handler. 484 + */ 485 + set_bit(IRQTF_DIED, &tsk->irqaction->flags); 486 + } 487 + 427 488 /* 428 489 * Internal function to register an irqaction - typically used to 429 490 * allocate special interrupts that are part of the architecture. ··· 541 434 * only the sysadmin is able to do this. 542 435 */ 543 436 rand_initialize_irq(irq); 437 + } 438 + 439 + /* 440 + * Threaded handler ? 441 + */ 442 + if (new->thread_fn) { 443 + struct task_struct *t; 444 + 445 + t = kthread_create(irq_thread, new, "irq/%d-%s", irq, 446 + new->name); 447 + if (IS_ERR(t)) 448 + return PTR_ERR(t); 449 + /* 450 + * We keep the reference to the task struct even if 451 + * the thread dies to avoid that the interrupt code 452 + * references an already freed task_struct. 453 + */ 454 + get_task_struct(t); 455 + new->thread = t; 456 + wake_up_process(t); 544 457 } 545 458 546 459 /* ··· 600 473 if (!shared) { 601 474 irq_chip_set_defaults(desc->chip); 602 475 476 + init_waitqueue_head(&desc->wait_for_threads); 477 + 603 478 /* Setup the type (level, edge polarity) if configured: */ 604 479 if (new->flags & IRQF_TRIGGER_MASK) { 605 480 ret = __irq_set_trigger(desc, irq, 606 481 new->flags & IRQF_TRIGGER_MASK); 607 482 608 - if (ret) { 609 - spin_unlock_irqrestore(&desc->lock, flags); 610 - return ret; 611 - } 483 + if (ret) 484 + goto out_thread; 612 485 } else 613 486 compat_irq_chip_set_default_handler(desc); 614 487 #if defined(CONFIG_IRQ_PER_CPU) ··· 676 549 dump_stack(); 677 550 } 678 551 #endif 552 + ret = -EBUSY; 553 + 554 + out_thread: 679 555 spin_unlock_irqrestore(&desc->lock, flags); 680 - return -EBUSY; 556 + if (new->thread) { 557 + struct task_struct *t = new->thread; 558 + 559 + new->thread = NULL; 560 + if (likely(!test_bit(IRQTF_DIED, &new->thread_flags))) 561 + kthread_stop(t); 562 + put_task_struct(t); 563 + } 564 + return ret; 681 565 } 682 566 683 567 /** ··· 714 576 { 715 577 struct irq_desc *desc = irq_to_desc(irq); 716 578 struct irqaction *action, **action_ptr; 579 + struct task_struct *irqthread; 717 580 unsigned long flags; 718 581 719 582 WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); ··· 761 622 else 762 623 desc->chip->disable(irq); 763 624 } 625 + 626 + irqthread = action->thread; 627 + action->thread = NULL; 628 + 764 629 spin_unlock_irqrestore(&desc->lock, flags); 765 630 766 631 unregister_handler_proc(irq, action); 767 632 768 633 /* Make sure it's not being used on another CPU: */ 769 634 synchronize_irq(irq); 635 + 636 + if (irqthread) { 637 + if (!test_bit(IRQTF_DIED, &action->thread_flags)) 638 + kthread_stop(irqthread); 639 + put_task_struct(irqthread); 640 + } 770 641 771 642 #ifdef CONFIG_DEBUG_SHIRQ 772 643 /* ··· 830 681 EXPORT_SYMBOL(free_irq); 831 682 832 683 /** 833 - * request_irq - allocate an interrupt line 684 + * request_threaded_irq - allocate an interrupt line 834 685 * @irq: Interrupt line to allocate 835 - * @handler: Function to be called when the IRQ occurs 686 + * @handler: Function to be called when the IRQ occurs. 687 + * Primary handler for threaded interrupts 688 + * @thread_fn: Function called from the irq handler thread 689 + * If NULL, no irq thread is created 836 690 * @irqflags: Interrupt type flags 837 691 * @devname: An ascii name for the claiming device 838 692 * @dev_id: A cookie passed back to the handler function ··· 846 694 * your handler function must clear any interrupt the board 847 695 * raises, you must take care both to initialise your hardware 848 696 * and to set up the interrupt handler in the right order. 697 + * 698 + * If you want to set up a threaded irq handler for your device 699 + * then you need to supply @handler and @thread_fn. @handler ist 700 + * still called in hard interrupt context and has to check 701 + * whether the interrupt originates from the device. If yes it 702 + * needs to disable the interrupt on the device and return 703 + * IRQ_THREAD_WAKE which will wake up the handler thread and run 704 + * @thread_fn. This split handler design is necessary to support 705 + * shared interrupts. 849 706 * 850 707 * Dev_id must be globally unique. Normally the address of the 851 708 * device data structure is used as the cookie. Since the handler ··· 871 710 * IRQF_TRIGGER_* Specify active edge(s) or level 872 711 * 873 712 */ 874 - int request_irq(unsigned int irq, irq_handler_t handler, 875 - unsigned long irqflags, const char *devname, void *dev_id) 713 + int request_threaded_irq(unsigned int irq, irq_handler_t handler, 714 + irq_handler_t thread_fn, unsigned long irqflags, 715 + const char *devname, void *dev_id) 876 716 { 877 717 struct irqaction *action; 878 718 struct irq_desc *desc; ··· 921 759 return -ENOMEM; 922 760 923 761 action->handler = handler; 762 + action->thread_fn = thread_fn; 924 763 action->flags = irqflags; 925 764 action->name = devname; 926 765 action->dev_id = dev_id; ··· 951 788 #endif 952 789 return retval; 953 790 } 954 - EXPORT_SYMBOL(request_irq); 791 + EXPORT_SYMBOL(request_threaded_irq);