diff options
Diffstat (limited to 'kernel/irq')
| -rw-r--r-- | kernel/irq/chip.c | 31 | ||||
| -rw-r--r-- | kernel/irq/irqdomain.c | 4 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 46 | ||||
| -rw-r--r-- | kernel/irq/proc.c | 2 | ||||
| -rw-r--r-- | kernel/irq/resend.c | 8 | ||||
| -rw-r--r-- | kernel/irq/spurious.c | 7 |
6 files changed, 80 insertions, 18 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 57d86d07221e..cbd97ce0b000 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -90,27 +90,41 @@ int irq_set_handler_data(unsigned int irq, void *data) | |||
| 90 | EXPORT_SYMBOL(irq_set_handler_data); | 90 | EXPORT_SYMBOL(irq_set_handler_data); |
| 91 | 91 | ||
| 92 | /** | 92 | /** |
| 93 | * irq_set_msi_desc - set MSI descriptor data for an irq | 93 | * irq_set_msi_desc_off - set MSI descriptor data for an irq at offset |
| 94 | * @irq: Interrupt number | 94 | * @irq_base: Interrupt number base |
| 95 | * @entry: Pointer to MSI descriptor data | 95 | * @irq_offset: Interrupt number offset |
| 96 | * @entry: Pointer to MSI descriptor data | ||
| 96 | * | 97 | * |
| 97 | * Set the MSI descriptor entry for an irq | 98 | * Set the MSI descriptor entry for an irq at offset |
| 98 | */ | 99 | */ |
| 99 | int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) | 100 | int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset, |
| 101 | struct msi_desc *entry) | ||
| 100 | { | 102 | { |
| 101 | unsigned long flags; | 103 | unsigned long flags; |
| 102 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); | 104 | struct irq_desc *desc = irq_get_desc_lock(irq_base + irq_offset, &flags, IRQ_GET_DESC_CHECK_GLOBAL); |
| 103 | 105 | ||
| 104 | if (!desc) | 106 | if (!desc) |
| 105 | return -EINVAL; | 107 | return -EINVAL; |
| 106 | desc->irq_data.msi_desc = entry; | 108 | desc->irq_data.msi_desc = entry; |
| 107 | if (entry) | 109 | if (entry && !irq_offset) |
| 108 | entry->irq = irq; | 110 | entry->irq = irq_base; |
| 109 | irq_put_desc_unlock(desc, flags); | 111 | irq_put_desc_unlock(desc, flags); |
| 110 | return 0; | 112 | return 0; |
| 111 | } | 113 | } |
| 112 | 114 | ||
| 113 | /** | 115 | /** |
| 116 | * irq_set_msi_desc - set MSI descriptor data for an irq | ||
| 117 | * @irq: Interrupt number | ||
| 118 | * @entry: Pointer to MSI descriptor data | ||
| 119 | * | ||
| 120 | * Set the MSI descriptor entry for an irq | ||
| 121 | */ | ||
| 122 | int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) | ||
| 123 | { | ||
| 124 | return irq_set_msi_desc_off(irq, 0, entry); | ||
| 125 | } | ||
| 126 | |||
| 127 | /** | ||
| 114 | * irq_set_chip_data - set irq chip data for an irq | 128 | * irq_set_chip_data - set irq chip data for an irq |
| 115 | * @irq: Interrupt number | 129 | * @irq: Interrupt number |
| 116 | * @data: Pointer to chip specific data | 130 | * @data: Pointer to chip specific data |
| @@ -272,6 +286,7 @@ void handle_nested_irq(unsigned int irq) | |||
| 272 | 286 | ||
| 273 | raw_spin_lock_irq(&desc->lock); | 287 | raw_spin_lock_irq(&desc->lock); |
| 274 | 288 | ||
| 289 | desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); | ||
| 275 | kstat_incr_irqs_this_cpu(irq, desc); | 290 | kstat_incr_irqs_this_cpu(irq, desc); |
| 276 | 291 | ||
| 277 | action = desc->action; | 292 | action = desc->action; |
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 4e69e24d3d7d..96f3a1d9c379 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
| @@ -177,8 +177,8 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node, | |||
| 177 | irq_base = irq_alloc_descs(first_irq, first_irq, size, | 177 | irq_base = irq_alloc_descs(first_irq, first_irq, size, |
| 178 | of_node_to_nid(of_node)); | 178 | of_node_to_nid(of_node)); |
| 179 | if (irq_base < 0) { | 179 | if (irq_base < 0) { |
| 180 | WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", | 180 | pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", |
| 181 | first_irq); | 181 | first_irq); |
| 182 | irq_base = first_irq; | 182 | irq_base = first_irq; |
| 183 | } | 183 | } |
| 184 | } else | 184 | } else |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 4c69326aa773..fa17855ca65a 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
| 19 | #include <linux/sched/rt.h> | ||
| 19 | #include <linux/task_work.h> | 20 | #include <linux/task_work.h> |
| 20 | 21 | ||
| 21 | #include "internals.h" | 22 | #include "internals.h" |
| @@ -616,6 +617,22 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | |||
| 616 | return ret; | 617 | return ret; |
| 617 | } | 618 | } |
| 618 | 619 | ||
| 620 | #ifdef CONFIG_HARDIRQS_SW_RESEND | ||
| 621 | int irq_set_parent(int irq, int parent_irq) | ||
| 622 | { | ||
| 623 | unsigned long flags; | ||
| 624 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); | ||
| 625 | |||
| 626 | if (!desc) | ||
| 627 | return -EINVAL; | ||
| 628 | |||
| 629 | desc->parent_irq = parent_irq; | ||
| 630 | |||
| 631 | irq_put_desc_unlock(desc, flags); | ||
| 632 | return 0; | ||
| 633 | } | ||
| 634 | #endif | ||
| 635 | |||
| 619 | /* | 636 | /* |
| 620 | * Default primary interrupt handler for threaded interrupts. Is | 637 | * Default primary interrupt handler for threaded interrupts. Is |
| 621 | * assigned as primary handler when request_threaded_irq is called | 638 | * assigned as primary handler when request_threaded_irq is called |
| @@ -716,6 +733,7 @@ static void | |||
| 716 | irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) | 733 | irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) |
| 717 | { | 734 | { |
| 718 | cpumask_var_t mask; | 735 | cpumask_var_t mask; |
| 736 | bool valid = true; | ||
| 719 | 737 | ||
| 720 | if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags)) | 738 | if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags)) |
| 721 | return; | 739 | return; |
| @@ -730,10 +748,18 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) | |||
| 730 | } | 748 | } |
| 731 | 749 | ||
| 732 | raw_spin_lock_irq(&desc->lock); | 750 | raw_spin_lock_irq(&desc->lock); |
| 733 | cpumask_copy(mask, desc->irq_data.affinity); | 751 | /* |
| 752 | * This code is triggered unconditionally. Check the affinity | ||
| 753 | * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out. | ||
| 754 | */ | ||
| 755 | if (desc->irq_data.affinity) | ||
| 756 | cpumask_copy(mask, desc->irq_data.affinity); | ||
| 757 | else | ||
| 758 | valid = false; | ||
| 734 | raw_spin_unlock_irq(&desc->lock); | 759 | raw_spin_unlock_irq(&desc->lock); |
| 735 | 760 | ||
| 736 | set_cpus_allowed_ptr(current, mask); | 761 | if (valid) |
| 762 | set_cpus_allowed_ptr(current, mask); | ||
| 737 | free_cpumask_var(mask); | 763 | free_cpumask_var(mask); |
| 738 | } | 764 | } |
| 739 | #else | 765 | #else |
| @@ -793,7 +819,7 @@ static void irq_thread_dtor(struct callback_head *unused) | |||
| 793 | action = kthread_data(tsk); | 819 | action = kthread_data(tsk); |
| 794 | 820 | ||
| 795 | pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", | 821 | pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", |
| 796 | tsk->comm ? tsk->comm : "", tsk->pid, action->irq); | 822 | tsk->comm, tsk->pid, action->irq); |
| 797 | 823 | ||
| 798 | 824 | ||
| 799 | desc = irq_to_desc(action->irq); | 825 | desc = irq_to_desc(action->irq); |
| @@ -833,6 +859,8 @@ static int irq_thread(void *data) | |||
| 833 | init_task_work(&on_exit_work, irq_thread_dtor); | 859 | init_task_work(&on_exit_work, irq_thread_dtor); |
| 834 | task_work_add(current, &on_exit_work, false); | 860 | task_work_add(current, &on_exit_work, false); |
| 835 | 861 | ||
| 862 | irq_thread_check_affinity(desc, action); | ||
| 863 | |||
| 836 | while (!irq_wait_for_interrupt(action)) { | 864 | while (!irq_wait_for_interrupt(action)) { |
| 837 | irqreturn_t action_ret; | 865 | irqreturn_t action_ret; |
| 838 | 866 | ||
| @@ -936,6 +964,16 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 936 | */ | 964 | */ |
| 937 | get_task_struct(t); | 965 | get_task_struct(t); |
| 938 | new->thread = t; | 966 | new->thread = t; |
| 967 | /* | ||
| 968 | * Tell the thread to set its affinity. This is | ||
| 969 | * important for shared interrupt handlers as we do | ||
| 970 | * not invoke setup_affinity() for the secondary | ||
| 971 | * handlers as everything is already set up. Even for | ||
| 972 | * interrupts marked with IRQF_NO_BALANCE this is | ||
| 973 | * correct as we want the thread to move to the cpu(s) | ||
| 974 | * on which the requesting code placed the interrupt. | ||
| 975 | */ | ||
| 976 | set_bit(IRQTF_AFFINITY, &new->thread_flags); | ||
| 939 | } | 977 | } |
| 940 | 978 | ||
| 941 | if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { | 979 | if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { |
| @@ -1487,6 +1525,7 @@ void enable_percpu_irq(unsigned int irq, unsigned int type) | |||
| 1487 | out: | 1525 | out: |
| 1488 | irq_put_desc_unlock(desc, flags); | 1526 | irq_put_desc_unlock(desc, flags); |
| 1489 | } | 1527 | } |
| 1528 | EXPORT_SYMBOL_GPL(enable_percpu_irq); | ||
| 1490 | 1529 | ||
| 1491 | void disable_percpu_irq(unsigned int irq) | 1530 | void disable_percpu_irq(unsigned int irq) |
| 1492 | { | 1531 | { |
| @@ -1500,6 +1539,7 @@ void disable_percpu_irq(unsigned int irq) | |||
| 1500 | irq_percpu_disable(desc, cpu); | 1539 | irq_percpu_disable(desc, cpu); |
| 1501 | irq_put_desc_unlock(desc, flags); | 1540 | irq_put_desc_unlock(desc, flags); |
| 1502 | } | 1541 | } |
| 1542 | EXPORT_SYMBOL_GPL(disable_percpu_irq); | ||
| 1503 | 1543 | ||
| 1504 | /* | 1544 | /* |
| 1505 | * Internal function to unregister a percpu irqaction. | 1545 | * Internal function to unregister a percpu irqaction. |
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 4bd4faa6323a..397db02209ed 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c | |||
| @@ -76,7 +76,7 @@ static int irq_affinity_list_proc_show(struct seq_file *m, void *v) | |||
| 76 | static ssize_t write_irq_affinity(int type, struct file *file, | 76 | static ssize_t write_irq_affinity(int type, struct file *file, |
| 77 | const char __user *buffer, size_t count, loff_t *pos) | 77 | const char __user *buffer, size_t count, loff_t *pos) |
| 78 | { | 78 | { |
| 79 | unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data; | 79 | unsigned int irq = (int)(long)PDE(file_inode(file))->data; |
| 80 | cpumask_var_t new_value; | 80 | cpumask_var_t new_value; |
| 81 | int err; | 81 | int err; |
| 82 | 82 | ||
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 6454db7b6a4d..9065107f083e 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c | |||
| @@ -74,6 +74,14 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq) | |||
| 74 | if (!desc->irq_data.chip->irq_retrigger || | 74 | if (!desc->irq_data.chip->irq_retrigger || |
| 75 | !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) { | 75 | !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) { |
| 76 | #ifdef CONFIG_HARDIRQS_SW_RESEND | 76 | #ifdef CONFIG_HARDIRQS_SW_RESEND |
| 77 | /* | ||
| 78 | * If the interrupt has a parent irq and runs | ||
| 79 | * in the thread context of the parent irq, | ||
| 80 | * retrigger the parent. | ||
| 81 | */ | ||
| 82 | if (desc->parent_irq && | ||
| 83 | irq_settings_is_nested_thread(desc)) | ||
| 84 | irq = desc->parent_irq; | ||
| 77 | /* Set it pending and activate the softirq: */ | 85 | /* Set it pending and activate the softirq: */ |
| 78 | set_bit(irq, irqs_resend); | 86 | set_bit(irq, irqs_resend); |
| 79 | tasklet_schedule(&resend_tasklet); | 87 | tasklet_schedule(&resend_tasklet); |
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index 611cd6003c45..7b5f012bde9d 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c | |||
| @@ -80,13 +80,11 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force) | |||
| 80 | 80 | ||
| 81 | /* | 81 | /* |
| 82 | * All handlers must agree on IRQF_SHARED, so we test just the | 82 | * All handlers must agree on IRQF_SHARED, so we test just the |
| 83 | * first. Check for action->next as well. | 83 | * first. |
| 84 | */ | 84 | */ |
| 85 | action = desc->action; | 85 | action = desc->action; |
| 86 | if (!action || !(action->flags & IRQF_SHARED) || | 86 | if (!action || !(action->flags & IRQF_SHARED) || |
| 87 | (action->flags & __IRQF_TIMER) || | 87 | (action->flags & __IRQF_TIMER)) |
| 88 | (action->handler(irq, action->dev_id) == IRQ_HANDLED) || | ||
| 89 | !action->next) | ||
| 90 | goto out; | 88 | goto out; |
| 91 | 89 | ||
| 92 | /* Already running on another processor */ | 90 | /* Already running on another processor */ |
| @@ -104,6 +102,7 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force) | |||
| 104 | do { | 102 | do { |
| 105 | if (handle_irq_event(desc) == IRQ_HANDLED) | 103 | if (handle_irq_event(desc) == IRQ_HANDLED) |
| 106 | ret = IRQ_HANDLED; | 104 | ret = IRQ_HANDLED; |
| 105 | /* Make sure that there is still a valid action */ | ||
| 107 | action = desc->action; | 106 | action = desc->action; |
| 108 | } while ((desc->istate & IRQS_PENDING) && action); | 107 | } while ((desc->istate & IRQS_PENDING) && action); |
| 109 | desc->istate &= ~IRQS_POLL_INPROGRESS; | 108 | desc->istate &= ~IRQS_POLL_INPROGRESS; |
