1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 /* 2 /* >> 3 * linux/kernel/irq/autoprobe.c >> 4 * 3 * Copyright (C) 1992, 1998-2004 Linus Torvald 5 * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar 4 * 6 * 5 * This file contains the interrupt probing co 7 * This file contains the interrupt probing code and driver APIs. 6 */ 8 */ 7 9 8 #include <linux/irq.h> 10 #include <linux/irq.h> 9 #include <linux/module.h> 11 #include <linux/module.h> 10 #include <linux/interrupt.h> 12 #include <linux/interrupt.h> 11 #include <linux/delay.h> 13 #include <linux/delay.h> 12 #include <linux/async.h> 14 #include <linux/async.h> 13 15 14 #include "internals.h" 16 #include "internals.h" 15 17 16 /* 18 /* 17 * Autodetection depends on the fact that any 19 * Autodetection depends on the fact that any interrupt that 18 * comes in on to an unassigned handler will g 20 * comes in on to an unassigned handler will get stuck with 19 * "IRQS_WAITING" cleared and the interrupt di 21 * "IRQS_WAITING" cleared and the interrupt disabled. 20 */ 22 */ 21 static DEFINE_MUTEX(probing_active); 23 static DEFINE_MUTEX(probing_active); 22 24 23 /** 25 /** 24 * probe_irq_on - begin an interrupt a 26 * probe_irq_on - begin an interrupt autodetect 25 * 27 * 26 * Commence probing for an interrupt. The 28 * Commence probing for an interrupt. The interrupts are scanned 27 * and a mask of potential interrupt line 29 * and a mask of potential interrupt lines is returned. 28 * 30 * 29 */ 31 */ 30 unsigned long probe_irq_on(void) 32 unsigned long probe_irq_on(void) 31 { 33 { 32 struct irq_desc *desc; 34 struct irq_desc *desc; 33 unsigned long mask = 0; 35 unsigned long mask = 0; 34 int i; 36 int i; 35 37 36 /* 38 /* 37 * quiesce the kernel, or at least the 39 * quiesce the kernel, or at least the asynchronous portion 38 */ 40 */ 39 async_synchronize_full(); 41 async_synchronize_full(); 40 mutex_lock(&probing_active); 42 mutex_lock(&probing_active); 41 /* 43 /* 42 * something may have generated an irq 44 * something may have generated an irq long ago and we want to 43 * flush such a longstanding irq befor 45 * flush such a longstanding irq before considering it as spurious. 44 */ 46 */ 45 for_each_irq_desc_reverse(i, desc) { 47 for_each_irq_desc_reverse(i, desc) { 46 raw_spin_lock_irq(&desc->lock) 48 raw_spin_lock_irq(&desc->lock); 47 if (!desc->action && irq_setti 49 if (!desc->action && irq_settings_can_probe(desc)) { 48 /* 50 /* 49 * Some chips need to 51 * Some chips need to know about probing in 50 * progress: 52 * progress: 51 */ 53 */ 52 if (desc->irq_data.chi 54 if (desc->irq_data.chip->irq_set_type) 53 desc->irq_data 55 desc->irq_data.chip->irq_set_type(&desc->irq_data, 54 56 IRQ_TYPE_PROBE); 55 irq_activate_and_start 57 irq_activate_and_startup(desc, IRQ_NORESEND); 56 } 58 } 57 raw_spin_unlock_irq(&desc->loc 59 raw_spin_unlock_irq(&desc->lock); 58 } 60 } 59 61 60 /* Wait for longstanding interrupts to 62 /* Wait for longstanding interrupts to trigger. */ 61 msleep(20); 63 msleep(20); 62 64 63 /* 65 /* 64 * enable any unassigned irqs 66 * enable any unassigned irqs 65 * (we must startup again here because 67 * (we must startup again here because if a longstanding irq 66 * happened in the previous stage, it 68 * happened in the previous stage, it may have masked itself) 67 */ 69 */ 68 for_each_irq_desc_reverse(i, desc) { 70 for_each_irq_desc_reverse(i, desc) { 69 raw_spin_lock_irq(&desc->lock) 71 raw_spin_lock_irq(&desc->lock); 70 if (!desc->action && irq_setti 72 if (!desc->action && irq_settings_can_probe(desc)) { 71 desc->istate |= IRQS_A 73 desc->istate |= IRQS_AUTODETECT | IRQS_WAITING; 72 if (irq_activate_and_s 74 if (irq_activate_and_startup(desc, IRQ_NORESEND)) 73 desc->istate | 75 desc->istate |= IRQS_PENDING; 74 } 76 } 75 raw_spin_unlock_irq(&desc->loc 77 raw_spin_unlock_irq(&desc->lock); 76 } 78 } 77 79 78 /* 80 /* 79 * Wait for spurious interrupts to tri 81 * Wait for spurious interrupts to trigger 80 */ 82 */ 81 msleep(100); 83 msleep(100); 82 84 83 /* 85 /* 84 * Now filter out any obviously spurio 86 * Now filter out any obviously spurious interrupts 85 */ 87 */ 86 for_each_irq_desc(i, desc) { 88 for_each_irq_desc(i, desc) { 87 raw_spin_lock_irq(&desc->lock) 89 raw_spin_lock_irq(&desc->lock); 88 90 89 if (desc->istate & IRQS_AUTODE 91 if (desc->istate & IRQS_AUTODETECT) { 90 /* It triggered alread 92 /* It triggered already - consider it spurious. */ 91 if (!(desc->istate & I 93 if (!(desc->istate & IRQS_WAITING)) { 92 desc->istate & 94 desc->istate &= ~IRQS_AUTODETECT; 93 irq_shutdown_a !! 95 irq_shutdown(desc); 94 } else 96 } else 95 if (i < 32) 97 if (i < 32) 96 mask | 98 mask |= 1 << i; 97 } 99 } 98 raw_spin_unlock_irq(&desc->loc 100 raw_spin_unlock_irq(&desc->lock); 99 } 101 } 100 102 101 return mask; 103 return mask; 102 } 104 } 103 EXPORT_SYMBOL(probe_irq_on); 105 EXPORT_SYMBOL(probe_irq_on); 104 106 105 /** 107 /** 106 * probe_irq_mask - scan a bitmap of inte 108 * probe_irq_mask - scan a bitmap of interrupt lines 107 * @val: mask of interrupts to consider 109 * @val: mask of interrupts to consider 108 * 110 * 109 * Scan the interrupt lines and return a 111 * Scan the interrupt lines and return a bitmap of active 110 * autodetect interrupts. The interrupt p 112 * autodetect interrupts. The interrupt probe logic state 111 * is then returned to its previous value 113 * is then returned to its previous value. 112 * 114 * 113 * Note: we need to scan all the irq's ev 115 * Note: we need to scan all the irq's even though we will 114 * only return autodetect irq numbers - j 116 * only return autodetect irq numbers - just so that we reset 115 * them all to a known state. 117 * them all to a known state. 116 */ 118 */ 117 unsigned int probe_irq_mask(unsigned long val) 119 unsigned int probe_irq_mask(unsigned long val) 118 { 120 { 119 unsigned int mask = 0; 121 unsigned int mask = 0; 120 struct irq_desc *desc; 122 struct irq_desc *desc; 121 int i; 123 int i; 122 124 123 for_each_irq_desc(i, desc) { 125 for_each_irq_desc(i, desc) { 124 raw_spin_lock_irq(&desc->lock) 126 raw_spin_lock_irq(&desc->lock); 125 if (desc->istate & IRQS_AUTODE 127 if (desc->istate & IRQS_AUTODETECT) { 126 if (i < 16 && !(desc-> 128 if (i < 16 && !(desc->istate & IRQS_WAITING)) 127 mask |= 1 << i 129 mask |= 1 << i; 128 130 129 desc->istate &= ~IRQS_ 131 desc->istate &= ~IRQS_AUTODETECT; 130 irq_shutdown_and_deact !! 132 irq_shutdown(desc); 131 } 133 } 132 raw_spin_unlock_irq(&desc->loc 134 raw_spin_unlock_irq(&desc->lock); 133 } 135 } 134 mutex_unlock(&probing_active); 136 mutex_unlock(&probing_active); 135 137 136 return mask & val; 138 return mask & val; 137 } 139 } 138 EXPORT_SYMBOL(probe_irq_mask); 140 EXPORT_SYMBOL(probe_irq_mask); 139 141 140 /** 142 /** 141 * probe_irq_off - end an interrupt aut 143 * probe_irq_off - end an interrupt autodetect 142 * @val: mask of potential interrupts (un 144 * @val: mask of potential interrupts (unused) 143 * 145 * 144 * Scans the unused interrupt lines and r 146 * Scans the unused interrupt lines and returns the line which 145 * appears to have triggered the interrup 147 * appears to have triggered the interrupt. If no interrupt was 146 * found then zero is returned. If more t 148 * found then zero is returned. If more than one interrupt is 147 * found then minus the first candidate i 149 * found then minus the first candidate is returned to indicate 148 * their is doubt. 150 * their is doubt. 149 * 151 * 150 * The interrupt probe logic state is ret 152 * The interrupt probe logic state is returned to its previous 151 * value. 153 * value. 152 * 154 * 153 * BUGS: When used in a module (which arg 155 * BUGS: When used in a module (which arguably shouldn't happen) 154 * nothing prevents two IRQ probe callers 156 * nothing prevents two IRQ probe callers from overlapping. The 155 * results of this are non-optimal. 157 * results of this are non-optimal. 156 */ 158 */ 157 int probe_irq_off(unsigned long val) 159 int probe_irq_off(unsigned long val) 158 { 160 { 159 int i, irq_found = 0, nr_of_irqs = 0; 161 int i, irq_found = 0, nr_of_irqs = 0; 160 struct irq_desc *desc; 162 struct irq_desc *desc; 161 163 162 for_each_irq_desc(i, desc) { 164 for_each_irq_desc(i, desc) { 163 raw_spin_lock_irq(&desc->lock) 165 raw_spin_lock_irq(&desc->lock); 164 166 165 if (desc->istate & IRQS_AUTODE 167 if (desc->istate & IRQS_AUTODETECT) { 166 if (!(desc->istate & I 168 if (!(desc->istate & IRQS_WAITING)) { 167 if (!nr_of_irq 169 if (!nr_of_irqs) 168 irq_fo 170 irq_found = i; 169 nr_of_irqs++; 171 nr_of_irqs++; 170 } 172 } 171 desc->istate &= ~IRQS_ 173 desc->istate &= ~IRQS_AUTODETECT; 172 irq_shutdown_and_deact !! 174 irq_shutdown(desc); 173 } 175 } 174 raw_spin_unlock_irq(&desc->loc 176 raw_spin_unlock_irq(&desc->lock); 175 } 177 } 176 mutex_unlock(&probing_active); 178 mutex_unlock(&probing_active); 177 179 178 if (nr_of_irqs > 1) 180 if (nr_of_irqs > 1) 179 irq_found = -irq_found; 181 irq_found = -irq_found; 180 182 181 return irq_found; 183 return irq_found; 182 } 184 } 183 EXPORT_SYMBOL(probe_irq_off); 185 EXPORT_SYMBOL(probe_irq_off); 184 186 185 187
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.