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