Blame view

kernel/irq/chip.c 35.3 KB
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
1
2
3
4
5
6
7
8
9
  /*
   * linux/kernel/irq/chip.c
   *
   * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
   * Copyright (C) 2005-2006, Thomas Gleixner, Russell King
   *
   * This file contains the core interrupt handling code, for irq-chip
   * based architectures.
   *
c0c6e0850   Mauro Carvalho Chehab   irq: update gener...
10
   * Detailed information is available in Documentation/core-api/genericirq.rst
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
11
12
13
   */
  
  #include <linux/irq.h>
7fe3730de   Michael Ellerman   MSI: arch must co...
14
  #include <linux/msi.h>
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
15
16
17
  #include <linux/module.h>
  #include <linux/interrupt.h>
  #include <linux/kernel_stat.h>
f8264e349   Jiang Liu   irqdomain: Introd...
18
  #include <linux/irqdomain.h>
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
19

f069686e4   Steven Rostedt   tracing/softirq: ...
20
  #include <trace/events/irq.h>
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
21
  #include "internals.h"
e509bd7da   Mika Westerberg   genirq: Allow mig...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  static irqreturn_t bad_chained_irq(int irq, void *dev_id)
  {
  	WARN_ONCE(1, "Chained irq %d should not call an action
  ", irq);
  	return IRQ_NONE;
  }
  
  /*
   * Chained handlers should never call action on their IRQ. This default
   * action will emit warning if such thing happens.
   */
  struct irqaction chained_action = {
  	.handler = bad_chained_irq,
  };
3a16d7136   Eric W. Biederman   [PATCH] genirq: i...
36
  /**
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
37
   *	irq_set_chip - set the irq chip for an irq
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
38
39
40
   *	@irq:	irq number
   *	@chip:	pointer to irq chip description structure
   */
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
41
  int irq_set_chip(unsigned int irq, struct irq_chip *chip)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
42
  {
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
43
  	unsigned long flags;
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
44
  	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
45

02725e747   Thomas Gleixner   genirq: Use irq_g...
46
  	if (!desc)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
47
  		return -EINVAL;
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
48
49
50
  
  	if (!chip)
  		chip = &no_irq_chip;
6b8ff3120   Thomas Gleixner   genirq: Convert c...
51
  	desc->irq_data.chip = chip;
02725e747   Thomas Gleixner   genirq: Use irq_g...
52
  	irq_put_desc_unlock(desc, flags);
d72274e58   David Daney   genirq: Reserve t...
53
54
  	/*
  	 * For !CONFIG_SPARSE_IRQ make the irq show up in
f63b6a05f   Thomas Gleixner   genirq: Replace r...
55
  	 * allocated_irqs.
d72274e58   David Daney   genirq: Reserve t...
56
  	 */
f63b6a05f   Thomas Gleixner   genirq: Replace r...
57
  	irq_mark_irq(irq);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
58
59
  	return 0;
  }
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
60
  EXPORT_SYMBOL(irq_set_chip);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
61
62
  
  /**
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
63
   *	irq_set_type - set the irq trigger type for an irq
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
64
   *	@irq:	irq number
0c5d1eb77   David Brownell   genirq: record tr...
65
   *	@type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
66
   */
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
67
  int irq_set_irq_type(unsigned int irq, unsigned int type)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
68
  {
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
69
  	unsigned long flags;
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
70
  	struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
02725e747   Thomas Gleixner   genirq: Use irq_g...
71
  	int ret = 0;
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
72

02725e747   Thomas Gleixner   genirq: Use irq_g...
73
74
  	if (!desc)
  		return -EINVAL;
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
75

a1ff541a4   Jiang Liu   genirq: Remove ir...
76
  	ret = __irq_set_trigger(desc, type);
02725e747   Thomas Gleixner   genirq: Use irq_g...
77
  	irq_put_desc_busunlock(desc, flags);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
78
79
  	return ret;
  }
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
80
  EXPORT_SYMBOL(irq_set_irq_type);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
81
82
  
  /**
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
83
   *	irq_set_handler_data - set irq handler data for an irq
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
84
85
86
87
88
   *	@irq:	Interrupt number
   *	@data:	Pointer to interrupt specific data
   *
   *	Set the hardware irq controller data for an irq
   */
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
89
  int irq_set_handler_data(unsigned int irq, void *data)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
90
  {
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
91
  	unsigned long flags;
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
92
  	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
93

02725e747   Thomas Gleixner   genirq: Use irq_g...
94
  	if (!desc)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
95
  		return -EINVAL;
af7080e04   Jiang Liu   genirq: Move fiel...
96
  	desc->irq_common_data.handler_data = data;
02725e747   Thomas Gleixner   genirq: Use irq_g...
97
  	irq_put_desc_unlock(desc, flags);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
98
99
  	return 0;
  }
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
100
  EXPORT_SYMBOL(irq_set_handler_data);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
101
102
  
  /**
51906e779   Alexander Gordeev   x86/MSI: Support ...
103
104
105
106
   *	irq_set_msi_desc_off - set MSI descriptor data for an irq at offset
   *	@irq_base:	Interrupt number base
   *	@irq_offset:	Interrupt number offset
   *	@entry:		Pointer to MSI descriptor data
5b912c108   Eric W. Biederman   msi: Kill the msi...
107
   *
51906e779   Alexander Gordeev   x86/MSI: Support ...
108
   *	Set the MSI descriptor entry for an irq at offset
5b912c108   Eric W. Biederman   msi: Kill the msi...
109
   */
51906e779   Alexander Gordeev   x86/MSI: Support ...
110
111
  int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset,
  			 struct msi_desc *entry)
5b912c108   Eric W. Biederman   msi: Kill the msi...
112
  {
5b912c108   Eric W. Biederman   msi: Kill the msi...
113
  	unsigned long flags;
51906e779   Alexander Gordeev   x86/MSI: Support ...
114
  	struct irq_desc *desc = irq_get_desc_lock(irq_base + irq_offset, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
5b912c108   Eric W. Biederman   msi: Kill the msi...
115

02725e747   Thomas Gleixner   genirq: Use irq_g...
116
  	if (!desc)
5b912c108   Eric W. Biederman   msi: Kill the msi...
117
  		return -EINVAL;
b237721c5   Jiang Liu   genirq: Move fiel...
118
  	desc->irq_common_data.msi_desc = entry;
51906e779   Alexander Gordeev   x86/MSI: Support ...
119
120
  	if (entry && !irq_offset)
  		entry->irq = irq_base;
02725e747   Thomas Gleixner   genirq: Use irq_g...
121
  	irq_put_desc_unlock(desc, flags);
5b912c108   Eric W. Biederman   msi: Kill the msi...
122
123
124
125
  	return 0;
  }
  
  /**
51906e779   Alexander Gordeev   x86/MSI: Support ...
126
127
128
129
130
131
132
133
134
135
136
137
   *	irq_set_msi_desc - set MSI descriptor data for an irq
   *	@irq:	Interrupt number
   *	@entry:	Pointer to MSI descriptor data
   *
   *	Set the MSI descriptor entry for an irq
   */
  int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)
  {
  	return irq_set_msi_desc_off(irq, 0, entry);
  }
  
  /**
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
138
   *	irq_set_chip_data - set irq chip data for an irq
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
139
140
141
142
143
   *	@irq:	Interrupt number
   *	@data:	Pointer to chip specific data
   *
   *	Set the hardware irq chip data for an irq
   */
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
144
  int irq_set_chip_data(unsigned int irq, void *data)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
145
  {
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
146
  	unsigned long flags;
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
147
  	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
148

02725e747   Thomas Gleixner   genirq: Use irq_g...
149
  	if (!desc)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
150
  		return -EINVAL;
6b8ff3120   Thomas Gleixner   genirq: Convert c...
151
  	desc->irq_data.chip_data = data;
02725e747   Thomas Gleixner   genirq: Use irq_g...
152
  	irq_put_desc_unlock(desc, flags);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
153
154
  	return 0;
  }
a0cd9ca2b   Thomas Gleixner   genirq: Namespace...
155
  EXPORT_SYMBOL(irq_set_chip_data);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
156

f303a6dd1   Thomas Gleixner   genirq: Sanitize ...
157
158
159
160
161
162
163
  struct irq_data *irq_get_irq_data(unsigned int irq)
  {
  	struct irq_desc *desc = irq_to_desc(irq);
  
  	return desc ? &desc->irq_data : NULL;
  }
  EXPORT_SYMBOL_GPL(irq_get_irq_data);
c1594b77e   Thomas Gleixner   genirq: Move IRQ_...
164
165
  static void irq_state_clr_disabled(struct irq_desc *desc)
  {
801a0e9ae   Thomas Gleixner   genirq: Add irq d...
166
  	irqd_clear(&desc->irq_data, IRQD_IRQ_DISABLED);
c1594b77e   Thomas Gleixner   genirq: Move IRQ_...
167
  }
6e40262ea   Thomas Gleixner   genirq: Move IRQ_...
168
169
  static void irq_state_clr_masked(struct irq_desc *desc)
  {
32f4125eb   Thomas Gleixner   genirq: Move INPR...
170
  	irqd_clear(&desc->irq_data, IRQD_IRQ_MASKED);
6e40262ea   Thomas Gleixner   genirq: Move IRQ_...
171
  }
201d7f47f   Thomas Gleixner   genirq: Handle NO...
172
173
174
175
176
177
178
179
180
  static void irq_state_clr_started(struct irq_desc *desc)
  {
  	irqd_clear(&desc->irq_data, IRQD_IRQ_STARTED);
  }
  
  static void irq_state_set_started(struct irq_desc *desc)
  {
  	irqd_set(&desc->irq_data, IRQD_IRQ_STARTED);
  }
761ea388e   Thomas Gleixner   genirq: Handle ma...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  enum {
  	IRQ_STARTUP_NORMAL,
  	IRQ_STARTUP_MANAGED,
  	IRQ_STARTUP_ABORT,
  };
  
  #ifdef CONFIG_SMP
  static int
  __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
  {
  	struct irq_data *d = irq_desc_get_irq_data(desc);
  
  	if (!irqd_affinity_is_managed(d))
  		return IRQ_STARTUP_NORMAL;
  
  	irqd_clr_managed_shutdown(d);
9cb067ef8   Thomas Gleixner   genirq: Fix cpuma...
197
  	if (cpumask_any_and(aff, cpu_online_mask) >= nr_cpu_ids) {
761ea388e   Thomas Gleixner   genirq: Handle ma...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  		/*
  		 * Catch code which fiddles with enable_irq() on a managed
  		 * and potentially shutdown IRQ. Chained interrupt
  		 * installment or irq auto probing should not happen on
  		 * managed irqs either. Emit a warning, break the affinity
  		 * and start it up as a normal interrupt.
  		 */
  		if (WARN_ON_ONCE(force))
  			return IRQ_STARTUP_NORMAL;
  		/*
  		 * The interrupt was requested, but there is no online CPU
  		 * in it's affinity mask. Put it into managed shutdown
  		 * state and let the cpu hotplug mechanism start it up once
  		 * a CPU in the mask becomes available.
  		 */
  		irqd_set_managed_shutdown(d);
  		return IRQ_STARTUP_ABORT;
  	}
  	return IRQ_STARTUP_MANAGED;
  }
  #else
2372a519f   Geert Uytterhoeven   genirq: Force inl...
219
  static __always_inline int
761ea388e   Thomas Gleixner   genirq: Handle ma...
220
221
222
223
224
  __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
  {
  	return IRQ_STARTUP_NORMAL;
  }
  #endif
708d174b6   Thomas Gleixner   genirq: Split out...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  static int __irq_startup(struct irq_desc *desc)
  {
  	struct irq_data *d = irq_desc_get_irq_data(desc);
  	int ret = 0;
  
  	irq_domain_activate_irq(d);
  	if (d->chip->irq_startup) {
  		ret = d->chip->irq_startup(d);
  		irq_state_clr_disabled(desc);
  		irq_state_clr_masked(desc);
  	} else {
  		irq_enable(desc);
  	}
  	irq_state_set_started(desc);
  	return ret;
  }
4cde9c6b8   Thomas Gleixner   genirq: Add force...
241
  int irq_startup(struct irq_desc *desc, bool resend, bool force)
469992386   Thomas Gleixner   genirq: Consolida...
242
  {
761ea388e   Thomas Gleixner   genirq: Handle ma...
243
244
  	struct irq_data *d = irq_desc_get_irq_data(desc);
  	struct cpumask *aff = irq_data_get_affinity_mask(d);
b4bc724e8   Thomas Gleixner   genirq: Handle pe...
245
  	int ret = 0;
469992386   Thomas Gleixner   genirq: Consolida...
246
  	desc->depth = 0;
761ea388e   Thomas Gleixner   genirq: Handle ma...
247
  	if (irqd_is_started(d)) {
b4bc724e8   Thomas Gleixner   genirq: Handle pe...
248
  		irq_enable(desc);
201d7f47f   Thomas Gleixner   genirq: Handle NO...
249
  	} else {
761ea388e   Thomas Gleixner   genirq: Handle ma...
250
251
252
253
254
255
  		switch (__irq_startup_managed(desc, aff, force)) {
  		case IRQ_STARTUP_NORMAL:
  			ret = __irq_startup(desc);
  			irq_setup_affinity(desc);
  			break;
  		case IRQ_STARTUP_MANAGED:
e43b3b585   Thomas Gleixner   genirq/cpuhotplug...
256
  			irq_do_set_affinity(d, aff, false);
761ea388e   Thomas Gleixner   genirq: Handle ma...
257
  			ret = __irq_startup(desc);
761ea388e   Thomas Gleixner   genirq: Handle ma...
258
259
260
261
  			break;
  		case IRQ_STARTUP_ABORT:
  			return 0;
  		}
3aae994fb   Thomas Gleixner   genirq: Consolida...
262
  	}
b4bc724e8   Thomas Gleixner   genirq: Handle pe...
263
  	if (resend)
0798abeb7   Jiang Liu   genirq: Remove th...
264
  		check_irq_resend(desc);
201d7f47f   Thomas Gleixner   genirq: Handle NO...
265

b4bc724e8   Thomas Gleixner   genirq: Handle pe...
266
  	return ret;
469992386   Thomas Gleixner   genirq: Consolida...
267
  }
201d7f47f   Thomas Gleixner   genirq: Handle NO...
268
  static void __irq_disable(struct irq_desc *desc, bool mask);
469992386   Thomas Gleixner   genirq: Consolida...
269
270
  void irq_shutdown(struct irq_desc *desc)
  {
201d7f47f   Thomas Gleixner   genirq: Handle NO...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  	if (irqd_is_started(&desc->irq_data)) {
  		desc->depth = 1;
  		if (desc->irq_data.chip->irq_shutdown) {
  			desc->irq_data.chip->irq_shutdown(&desc->irq_data);
  			irq_state_set_disabled(desc);
  			irq_state_set_masked(desc);
  		} else {
  			__irq_disable(desc, true);
  		}
  		irq_state_clr_started(desc);
  	}
  	/*
  	 * This must be called even if the interrupt was never started up,
  	 * because the activation can happen before the interrupt is
  	 * available for request/startup. It has it's own state tracking so
  	 * it's safe to call it unconditionally.
  	 */
f8264e349   Jiang Liu   irqdomain: Introd...
288
  	irq_domain_deactivate_irq(&desc->irq_data);
469992386   Thomas Gleixner   genirq: Consolida...
289
  }
87923470c   Thomas Gleixner   genirq: Consolida...
290
291
  void irq_enable(struct irq_desc *desc)
  {
bf22ff45b   Jeffy Chen   genirq: Avoid unn...
292
293
294
295
296
297
298
299
300
301
302
  	if (!irqd_irq_disabled(&desc->irq_data)) {
  		unmask_irq(desc);
  	} else {
  		irq_state_clr_disabled(desc);
  		if (desc->irq_data.chip->irq_enable) {
  			desc->irq_data.chip->irq_enable(&desc->irq_data);
  			irq_state_clr_masked(desc);
  		} else {
  			unmask_irq(desc);
  		}
  	}
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
303
  }
201d7f47f   Thomas Gleixner   genirq: Handle NO...
304
305
  static void __irq_disable(struct irq_desc *desc, bool mask)
  {
bf22ff45b   Jeffy Chen   genirq: Avoid unn...
306
307
308
309
310
311
312
313
314
315
316
  	if (irqd_irq_disabled(&desc->irq_data)) {
  		if (mask)
  			mask_irq(desc);
  	} else {
  		irq_state_set_disabled(desc);
  		if (desc->irq_data.chip->irq_disable) {
  			desc->irq_data.chip->irq_disable(&desc->irq_data);
  			irq_state_set_masked(desc);
  		} else if (mask) {
  			mask_irq(desc);
  		}
201d7f47f   Thomas Gleixner   genirq: Handle NO...
317
318
  	}
  }
d671a6055   Andreas Fenkart   genirq: Add kerne...
319
  /**
f788e7bf0   Xie XiuQi   irq: Fix some tri...
320
   * irq_disable - Mark interrupt disabled
d671a6055   Andreas Fenkart   genirq: Add kerne...
321
322
323
324
325
326
327
328
329
330
   * @desc:	irq descriptor which should be disabled
   *
   * If the chip does not implement the irq_disable callback, we
   * use a lazy disable approach. That means we mark the interrupt
   * disabled, but leave the hardware unmasked. That's an
   * optimization because we avoid the hardware access for the
   * common case where no interrupt happens after we marked it
   * disabled. If an interrupt happens, then the interrupt flow
   * handler masks the line at the hardware level and marks it
   * pending.
e9849777d   Thomas Gleixner   genirq: Add flag ...
331
332
333
334
335
336
337
   *
   * If the interrupt chip does not implement the irq_disable callback,
   * a driver can disable the lazy approach for a particular irq line by
   * calling 'irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY)'. This can
   * be used for devices which cannot disable the interrupt at the
   * device level under certain circumstances and have to use
   * disable_irq[_nosync] instead.
d671a6055   Andreas Fenkart   genirq: Add kerne...
338
   */
50f7c0327   Thomas Gleixner   genirq: Remove de...
339
  void irq_disable(struct irq_desc *desc)
89d694b9d   Thomas Gleixner   genirq: do not le...
340
  {
201d7f47f   Thomas Gleixner   genirq: Handle NO...
341
  	__irq_disable(desc, irq_settings_disable_unlazy(desc));
89d694b9d   Thomas Gleixner   genirq: do not le...
342
  }
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu)
  {
  	if (desc->irq_data.chip->irq_enable)
  		desc->irq_data.chip->irq_enable(&desc->irq_data);
  	else
  		desc->irq_data.chip->irq_unmask(&desc->irq_data);
  	cpumask_set_cpu(cpu, desc->percpu_enabled);
  }
  
  void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu)
  {
  	if (desc->irq_data.chip->irq_disable)
  		desc->irq_data.chip->irq_disable(&desc->irq_data);
  	else
  		desc->irq_data.chip->irq_mask(&desc->irq_data);
  	cpumask_clear_cpu(cpu, desc->percpu_enabled);
  }
9205e31d1   Thomas Gleixner   genirq: Provide c...
360
  static inline void mask_ack_irq(struct irq_desc *desc)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
361
  {
bf22ff45b   Jeffy Chen   genirq: Avoid unn...
362
  	if (desc->irq_data.chip->irq_mask_ack) {
9205e31d1   Thomas Gleixner   genirq: Provide c...
363
  		desc->irq_data.chip->irq_mask_ack(&desc->irq_data);
bf22ff45b   Jeffy Chen   genirq: Avoid unn...
364
365
366
  		irq_state_set_masked(desc);
  	} else {
  		mask_irq(desc);
22a49163e   Thomas Gleixner   genirq: Provide c...
367
368
  		if (desc->irq_data.chip->irq_ack)
  			desc->irq_data.chip->irq_ack(&desc->irq_data);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
369
  	}
0b1adaa03   Thomas Gleixner   genirq: Prevent o...
370
  }
d4d5e0896   Thomas Gleixner   genirq: Add IRQCH...
371
  void mask_irq(struct irq_desc *desc)
0b1adaa03   Thomas Gleixner   genirq: Prevent o...
372
  {
bf22ff45b   Jeffy Chen   genirq: Avoid unn...
373
374
  	if (irqd_irq_masked(&desc->irq_data))
  		return;
e2c0f8ff0   Thomas Gleixner   genirq: Provide c...
375
376
  	if (desc->irq_data.chip->irq_mask) {
  		desc->irq_data.chip->irq_mask(&desc->irq_data);
6e40262ea   Thomas Gleixner   genirq: Move IRQ_...
377
  		irq_state_set_masked(desc);
0b1adaa03   Thomas Gleixner   genirq: Prevent o...
378
379
  	}
  }
d4d5e0896   Thomas Gleixner   genirq: Add IRQCH...
380
  void unmask_irq(struct irq_desc *desc)
0b1adaa03   Thomas Gleixner   genirq: Prevent o...
381
  {
bf22ff45b   Jeffy Chen   genirq: Avoid unn...
382
383
  	if (!irqd_irq_masked(&desc->irq_data))
  		return;
0eda58b7f   Thomas Gleixner   genirq: Provide c...
384
385
  	if (desc->irq_data.chip->irq_unmask) {
  		desc->irq_data.chip->irq_unmask(&desc->irq_data);
6e40262ea   Thomas Gleixner   genirq: Move IRQ_...
386
  		irq_state_clr_masked(desc);
0b1adaa03   Thomas Gleixner   genirq: Prevent o...
387
  	}
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
388
  }
328a4978d   Thomas Gleixner   genirq: Add a new...
389
390
391
392
393
394
  void unmask_threaded_irq(struct irq_desc *desc)
  {
  	struct irq_chip *chip = desc->irq_data.chip;
  
  	if (chip->flags & IRQCHIP_EOI_THREADED)
  		chip->irq_eoi(&desc->irq_data);
bf22ff45b   Jeffy Chen   genirq: Avoid unn...
395
  	unmask_irq(desc);
328a4978d   Thomas Gleixner   genirq: Add a new...
396
  }
399b5da29   Thomas Gleixner   genirq: Support n...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  /*
   *	handle_nested_irq - Handle a nested irq from a irq thread
   *	@irq:	the interrupt number
   *
   *	Handle interrupts which are nested into a threaded interrupt
   *	handler. The handler function is called inside the calling
   *	threads context.
   */
  void handle_nested_irq(unsigned int irq)
  {
  	struct irq_desc *desc = irq_to_desc(irq);
  	struct irqaction *action;
  	irqreturn_t action_ret;
  
  	might_sleep();
239007b84   Thomas Gleixner   genirq: Convert i...
412
  	raw_spin_lock_irq(&desc->lock);
399b5da29   Thomas Gleixner   genirq: Support n...
413

293a7a0a1   Thomas Gleixner   genirq: Provide m...
414
  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
399b5da29   Thomas Gleixner   genirq: Support n...
415
416
  
  	action = desc->action;
23812b9d9   Ning Jiang   genirq: Add IRQS_...
417
418
  	if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) {
  		desc->istate |= IRQS_PENDING;
399b5da29   Thomas Gleixner   genirq: Support n...
419
  		goto out_unlock;
23812b9d9   Ning Jiang   genirq: Add IRQS_...
420
  	}
399b5da29   Thomas Gleixner   genirq: Support n...
421

a946e8c71   Sudeep Holla   genirq: Delay inc...
422
  	kstat_incr_irqs_this_cpu(desc);
32f4125eb   Thomas Gleixner   genirq: Move INPR...
423
  	irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
239007b84   Thomas Gleixner   genirq: Convert i...
424
  	raw_spin_unlock_irq(&desc->lock);
399b5da29   Thomas Gleixner   genirq: Support n...
425

45e520221   Charles Keepax   genirq: Add suppo...
426
427
428
  	action_ret = IRQ_NONE;
  	for_each_action_of_desc(desc, action)
  		action_ret |= action->thread_fn(action->irq, action->dev_id);
399b5da29   Thomas Gleixner   genirq: Support n...
429
  	if (!noirqdebug)
0dcdbc975   Jiang Liu   genirq: Remove th...
430
  		note_interrupt(desc, action_ret);
399b5da29   Thomas Gleixner   genirq: Support n...
431

239007b84   Thomas Gleixner   genirq: Convert i...
432
  	raw_spin_lock_irq(&desc->lock);
32f4125eb   Thomas Gleixner   genirq: Move INPR...
433
  	irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
399b5da29   Thomas Gleixner   genirq: Support n...
434
435
  
  out_unlock:
239007b84   Thomas Gleixner   genirq: Convert i...
436
  	raw_spin_unlock_irq(&desc->lock);
399b5da29   Thomas Gleixner   genirq: Support n...
437
438
  }
  EXPORT_SYMBOL_GPL(handle_nested_irq);
fe200ae48   Thomas Gleixner   genirq: Mark poll...
439
440
  static bool irq_check_poll(struct irq_desc *desc)
  {
6954b75b4   Thomas Gleixner   genirq: Move IRQ_...
441
  	if (!(desc->istate & IRQS_POLL_INPROGRESS))
fe200ae48   Thomas Gleixner   genirq: Mark poll...
442
443
444
  		return false;
  	return irq_wait_for_poll(desc);
  }
c7bd3ec05   Thomas Gleixner   genirq: Create he...
445
446
  static bool irq_may_run(struct irq_desc *desc)
  {
9ce7a2584   Thomas Gleixner   genirq: Simplify ...
447
448
449
450
451
452
453
  	unsigned int mask = IRQD_IRQ_INPROGRESS | IRQD_WAKEUP_ARMED;
  
  	/*
  	 * If the interrupt is not in progress and is not an armed
  	 * wakeup interrupt, proceed.
  	 */
  	if (!irqd_has_set(&desc->irq_data, mask))
c7bd3ec05   Thomas Gleixner   genirq: Create he...
454
  		return true;
9ce7a2584   Thomas Gleixner   genirq: Simplify ...
455
456
457
458
459
460
461
462
463
464
465
466
  
  	/*
  	 * If the interrupt is an armed wakeup source, mark it pending
  	 * and suspended, disable it and notify the pm core about the
  	 * event.
  	 */
  	if (irq_pm_check_wakeup(desc))
  		return false;
  
  	/*
  	 * Handle a potential concurrent poll on a different core.
  	 */
c7bd3ec05   Thomas Gleixner   genirq: Create he...
467
468
  	return irq_check_poll(desc);
  }
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
469
470
  /**
   *	handle_simple_irq - Simple and software-decoded IRQs.
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
471
   *	@desc:	the interrupt description structure for this irq
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
472
473
474
475
476
477
478
479
   *
   *	Simple interrupts are either sent from a demultiplexing interrupt
   *	handler or come from hardware, where no interrupt hardware control
   *	is necessary.
   *
   *	Note: The caller is expected to handle the ack, clear, mask and
   *	unmask issues if necessary.
   */
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
480
  void handle_simple_irq(struct irq_desc *desc)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
481
  {
239007b84   Thomas Gleixner   genirq: Convert i...
482
  	raw_spin_lock(&desc->lock);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
483

c7bd3ec05   Thomas Gleixner   genirq: Create he...
484
485
  	if (!irq_may_run(desc))
  		goto out_unlock;
fe200ae48   Thomas Gleixner   genirq: Mark poll...
486

163ef3091   Thomas Gleixner   genirq: Move IRQ_...
487
  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
488

23812b9d9   Ning Jiang   genirq: Add IRQS_...
489
490
  	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
  		desc->istate |= IRQS_PENDING;
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
491
  		goto out_unlock;
23812b9d9   Ning Jiang   genirq: Add IRQS_...
492
  	}
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
493

a946e8c71   Sudeep Holla   genirq: Delay inc...
494
  	kstat_incr_irqs_this_cpu(desc);
107781e72   Thomas Gleixner   genirq: Use handl...
495
  	handle_irq_event(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
496

dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
497
  out_unlock:
239007b84   Thomas Gleixner   genirq: Convert i...
498
  	raw_spin_unlock(&desc->lock);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
499
  }
edf76f830   Jonathan Cameron   irq: Export funct...
500
  EXPORT_SYMBOL_GPL(handle_simple_irq);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
501

edd14cfeb   Keith Busch   genirq: Add untra...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
  /**
   *	handle_untracked_irq - Simple and software-decoded IRQs.
   *	@desc:	the interrupt description structure for this irq
   *
   *	Untracked interrupts are sent from a demultiplexing interrupt
   *	handler when the demultiplexer does not know which device it its
   *	multiplexed irq domain generated the interrupt. IRQ's handled
   *	through here are not subjected to stats tracking, randomness, or
   *	spurious interrupt detection.
   *
   *	Note: Like handle_simple_irq, the caller is expected to handle
   *	the ack, clear, mask and unmask issues if necessary.
   */
  void handle_untracked_irq(struct irq_desc *desc)
  {
  	unsigned int flags = 0;
  
  	raw_spin_lock(&desc->lock);
  
  	if (!irq_may_run(desc))
  		goto out_unlock;
  
  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
  
  	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
  		desc->istate |= IRQS_PENDING;
  		goto out_unlock;
  	}
  
  	desc->istate &= ~IRQS_PENDING;
  	irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
  	raw_spin_unlock(&desc->lock);
  
  	__handle_irq_event_percpu(desc, &flags);
  
  	raw_spin_lock(&desc->lock);
  	irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
  
  out_unlock:
  	raw_spin_unlock(&desc->lock);
  }
  EXPORT_SYMBOL_GPL(handle_untracked_irq);
ac5637611   Thomas Gleixner   genirq: Unmask on...
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
  /*
   * Called unconditionally from handle_level_irq() and only for oneshot
   * interrupts from handle_fasteoi_irq()
   */
  static void cond_unmask_irq(struct irq_desc *desc)
  {
  	/*
  	 * We need to unmask in the following cases:
  	 * - Standard level irq (IRQF_ONESHOT is not set)
  	 * - Oneshot irq which did not wake the thread (caused by a
  	 *   spurious interrupt or a primary handler handling it
  	 *   completely).
  	 */
  	if (!irqd_irq_disabled(&desc->irq_data) &&
  	    irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot)
  		unmask_irq(desc);
  }
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
561
562
  /**
   *	handle_level_irq - Level type irq handler
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
563
   *	@desc:	the interrupt description structure for this irq
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
564
565
566
567
568
569
   *
   *	Level type interrupts are active as long as the hardware line has
   *	the active level. This may require to mask the interrupt and unmask
   *	it after the associated handler has acknowledged the device, so the
   *	interrupt line is back to inactive.
   */
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
570
  void handle_level_irq(struct irq_desc *desc)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
571
  {
239007b84   Thomas Gleixner   genirq: Convert i...
572
  	raw_spin_lock(&desc->lock);
9205e31d1   Thomas Gleixner   genirq: Provide c...
573
  	mask_ack_irq(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
574

c7bd3ec05   Thomas Gleixner   genirq: Create he...
575
576
  	if (!irq_may_run(desc))
  		goto out_unlock;
fe200ae48   Thomas Gleixner   genirq: Mark poll...
577

163ef3091   Thomas Gleixner   genirq: Move IRQ_...
578
  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
579
580
581
582
583
  
  	/*
  	 * If its disabled or no action available
  	 * keep it masked and get out of here
  	 */
d4dc0f90d   Thomas Gleixner   genirq: Allow che...
584
585
  	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
  		desc->istate |= IRQS_PENDING;
86998aa65   Ingo Molnar   [PATCH] genirq co...
586
  		goto out_unlock;
d4dc0f90d   Thomas Gleixner   genirq: Allow che...
587
  	}
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
588

a946e8c71   Sudeep Holla   genirq: Delay inc...
589
  	kstat_incr_irqs_this_cpu(desc);
1529866c6   Thomas Gleixner   genirq: Use handl...
590
  	handle_irq_event(desc);
b25c340c1   Thomas Gleixner   genirq: Add onesh...
591

ac5637611   Thomas Gleixner   genirq: Unmask on...
592
  	cond_unmask_irq(desc);
86998aa65   Ingo Molnar   [PATCH] genirq co...
593
  out_unlock:
239007b84   Thomas Gleixner   genirq: Convert i...
594
  	raw_spin_unlock(&desc->lock);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
595
  }
14819ea1e   Ingo Molnar   irq: export __set...
596
  EXPORT_SYMBOL_GPL(handle_level_irq);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
597

781295762   Thomas Gleixner   genirq: Add prefl...
598
599
600
601
602
603
604
605
606
  #ifdef CONFIG_IRQ_PREFLOW_FASTEOI
  static inline void preflow_handler(struct irq_desc *desc)
  {
  	if (desc->preflow_handler)
  		desc->preflow_handler(&desc->irq_data);
  }
  #else
  static inline void preflow_handler(struct irq_desc *desc) { }
  #endif
328a4978d   Thomas Gleixner   genirq: Add a new...
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
  static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
  {
  	if (!(desc->istate & IRQS_ONESHOT)) {
  		chip->irq_eoi(&desc->irq_data);
  		return;
  	}
  	/*
  	 * We need to unmask in the following cases:
  	 * - Oneshot irq which did not wake the thread (caused by a
  	 *   spurious interrupt or a primary handler handling it
  	 *   completely).
  	 */
  	if (!irqd_irq_disabled(&desc->irq_data) &&
  	    irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
  		chip->irq_eoi(&desc->irq_data);
  		unmask_irq(desc);
  	} else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
  		chip->irq_eoi(&desc->irq_data);
  	}
  }
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
627
  /**
47c2a3aa4   Ingo Molnar   [PATCH] genirq: a...
628
   *	handle_fasteoi_irq - irq handler for transparent controllers
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
629
   *	@desc:	the interrupt description structure for this irq
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
630
   *
47c2a3aa4   Ingo Molnar   [PATCH] genirq: a...
631
   *	Only a single callback will be issued to the chip: an ->eoi()
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
632
633
634
635
   *	call when the interrupt has been serviced. This enables support
   *	for modern forms of interrupt handlers, which handle the flow
   *	details in hardware, transparently.
   */
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
636
  void handle_fasteoi_irq(struct irq_desc *desc)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
637
  {
328a4978d   Thomas Gleixner   genirq: Add a new...
638
  	struct irq_chip *chip = desc->irq_data.chip;
239007b84   Thomas Gleixner   genirq: Convert i...
639
  	raw_spin_lock(&desc->lock);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
640

c7bd3ec05   Thomas Gleixner   genirq: Create he...
641
642
  	if (!irq_may_run(desc))
  		goto out;
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
643

163ef3091   Thomas Gleixner   genirq: Move IRQ_...
644
  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
645
646
647
  
  	/*
  	 * If its disabled or no action available
76d216014   Ingo Molnar   [PATCH] genirq: d...
648
  	 * then mask it and get out of here:
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
649
  	 */
32f4125eb   Thomas Gleixner   genirq: Move INPR...
650
  	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
2a0d6fb33   Thomas Gleixner   genirq: Move IRQ_...
651
  		desc->istate |= IRQS_PENDING;
e2c0f8ff0   Thomas Gleixner   genirq: Provide c...
652
  		mask_irq(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
653
  		goto out;
98bb244b6   Benjamin Herrenschmidt   [PATCH] genirq: f...
654
  	}
c69e3758f   Thomas Gleixner   genirq: Fixup fas...
655

a946e8c71   Sudeep Holla   genirq: Delay inc...
656
  	kstat_incr_irqs_this_cpu(desc);
c69e3758f   Thomas Gleixner   genirq: Fixup fas...
657
658
  	if (desc->istate & IRQS_ONESHOT)
  		mask_irq(desc);
781295762   Thomas Gleixner   genirq: Add prefl...
659
  	preflow_handler(desc);
a7ae4de5c   Thomas Gleixner   genirq: Use handl...
660
  	handle_irq_event(desc);
77694b408   Thomas Gleixner   genirq; Add faste...
661

328a4978d   Thomas Gleixner   genirq: Add a new...
662
  	cond_unmask_eoi_irq(desc, chip);
ac5637611   Thomas Gleixner   genirq: Unmask on...
663

239007b84   Thomas Gleixner   genirq: Convert i...
664
  	raw_spin_unlock(&desc->lock);
77694b408   Thomas Gleixner   genirq; Add faste...
665
666
  	return;
  out:
328a4978d   Thomas Gleixner   genirq: Add a new...
667
668
669
  	if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
  		chip->irq_eoi(&desc->irq_data);
  	raw_spin_unlock(&desc->lock);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
670
  }
7cad45eea   Vincent Stehlé   irq: Export handl...
671
  EXPORT_SYMBOL_GPL(handle_fasteoi_irq);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
672
673
674
  
  /**
   *	handle_edge_irq - edge type IRQ handler
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
675
   *	@desc:	the interrupt description structure for this irq
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
676
677
   *
   *	Interrupt occures on the falling and/or rising edge of a hardware
25985edce   Lucas De Marchi   Fix common misspe...
678
   *	signal. The occurrence is latched into the irq controller hardware
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
679
680
   *	and must be acked in order to be reenabled. After the ack another
   *	interrupt can happen on the same source even before the first one
dfff0615d   Uwe Kleine-König   tree-wide: fix ty...
681
   *	is handled by the associated event handler. If this happens it
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
682
683
684
685
686
687
   *	might be necessary to disable (mask) the interrupt depending on the
   *	controller hardware. This requires to reenable the interrupt inside
   *	of the loop which handles the interrupts which have arrived while
   *	the handler was running. If all pending interrupts are handled, the
   *	loop is left.
   */
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
688
  void handle_edge_irq(struct irq_desc *desc)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
689
  {
239007b84   Thomas Gleixner   genirq: Convert i...
690
  	raw_spin_lock(&desc->lock);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
691

163ef3091   Thomas Gleixner   genirq: Move IRQ_...
692
  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
c3d7acd02   Thomas Gleixner   genirq: Distangle...
693

c7bd3ec05   Thomas Gleixner   genirq: Create he...
694
695
696
697
  	if (!irq_may_run(desc)) {
  		desc->istate |= IRQS_PENDING;
  		mask_ack_irq(desc);
  		goto out_unlock;
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
698
  	}
c3d7acd02   Thomas Gleixner   genirq: Distangle...
699

dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
700
  	/*
c3d7acd02   Thomas Gleixner   genirq: Distangle...
701
702
  	 * If its disabled or no action available then mask it and get
  	 * out of here.
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
703
  	 */
c3d7acd02   Thomas Gleixner   genirq: Distangle...
704
705
706
707
  	if (irqd_irq_disabled(&desc->irq_data) || !desc->action) {
  		desc->istate |= IRQS_PENDING;
  		mask_ack_irq(desc);
  		goto out_unlock;
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
708
  	}
c3d7acd02   Thomas Gleixner   genirq: Distangle...
709

b51bf95c5   Jiang Liu   genirq: Remove th...
710
  	kstat_incr_irqs_this_cpu(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
711
712
  
  	/* Start handling the irq */
22a49163e   Thomas Gleixner   genirq: Provide c...
713
  	desc->irq_data.chip->irq_ack(&desc->irq_data);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
714

dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
715
  	do {
a60a5dc2d   Thomas Gleixner   genirq: Use handl...
716
  		if (unlikely(!desc->action)) {
e2c0f8ff0   Thomas Gleixner   genirq: Provide c...
717
  			mask_irq(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
718
719
720
721
722
723
724
725
  			goto out_unlock;
  		}
  
  		/*
  		 * When another irq arrived while we were handling
  		 * one, we could have masked the irq.
  		 * Renable it, if it was not disabled in meantime.
  		 */
2a0d6fb33   Thomas Gleixner   genirq: Move IRQ_...
726
  		if (unlikely(desc->istate & IRQS_PENDING)) {
32f4125eb   Thomas Gleixner   genirq: Move INPR...
727
728
  			if (!irqd_irq_disabled(&desc->irq_data) &&
  			    irqd_irq_masked(&desc->irq_data))
c1594b77e   Thomas Gleixner   genirq: Move IRQ_...
729
  				unmask_irq(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
730
  		}
a60a5dc2d   Thomas Gleixner   genirq: Use handl...
731
  		handle_irq_event(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
732

2a0d6fb33   Thomas Gleixner   genirq: Move IRQ_...
733
  	} while ((desc->istate & IRQS_PENDING) &&
32f4125eb   Thomas Gleixner   genirq: Move INPR...
734
  		 !irqd_irq_disabled(&desc->irq_data));
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
735

dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
736
  out_unlock:
239007b84   Thomas Gleixner   genirq: Convert i...
737
  	raw_spin_unlock(&desc->lock);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
738
  }
3911ff30f   Jiri Kosina   genirq: export ha...
739
  EXPORT_SYMBOL(handle_edge_irq);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
740

0521c8fbb   Thomas Gleixner   genirq: Provide e...
741
742
743
  #ifdef CONFIG_IRQ_EDGE_EOI_HANDLER
  /**
   *	handle_edge_eoi_irq - edge eoi type IRQ handler
0521c8fbb   Thomas Gleixner   genirq: Provide e...
744
745
746
747
748
   *	@desc:	the interrupt description structure for this irq
   *
   * Similar as the above handle_edge_irq, but using eoi and w/o the
   * mask/unmask logic.
   */
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
749
  void handle_edge_eoi_irq(struct irq_desc *desc)
0521c8fbb   Thomas Gleixner   genirq: Provide e...
750
751
752
753
754
755
  {
  	struct irq_chip *chip = irq_desc_get_chip(desc);
  
  	raw_spin_lock(&desc->lock);
  
  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
c3d7acd02   Thomas Gleixner   genirq: Distangle...
756

c7bd3ec05   Thomas Gleixner   genirq: Create he...
757
758
759
  	if (!irq_may_run(desc)) {
  		desc->istate |= IRQS_PENDING;
  		goto out_eoi;
0521c8fbb   Thomas Gleixner   genirq: Provide e...
760
  	}
c3d7acd02   Thomas Gleixner   genirq: Distangle...
761

0521c8fbb   Thomas Gleixner   genirq: Provide e...
762
  	/*
c3d7acd02   Thomas Gleixner   genirq: Distangle...
763
764
  	 * If its disabled or no action available then mask it and get
  	 * out of here.
0521c8fbb   Thomas Gleixner   genirq: Provide e...
765
  	 */
c3d7acd02   Thomas Gleixner   genirq: Distangle...
766
767
768
  	if (irqd_irq_disabled(&desc->irq_data) || !desc->action) {
  		desc->istate |= IRQS_PENDING;
  		goto out_eoi;
0521c8fbb   Thomas Gleixner   genirq: Provide e...
769
  	}
c3d7acd02   Thomas Gleixner   genirq: Distangle...
770

b51bf95c5   Jiang Liu   genirq: Remove th...
771
  	kstat_incr_irqs_this_cpu(desc);
0521c8fbb   Thomas Gleixner   genirq: Provide e...
772
773
774
775
776
777
778
779
780
  
  	do {
  		if (unlikely(!desc->action))
  			goto out_eoi;
  
  		handle_irq_event(desc);
  
  	} while ((desc->istate & IRQS_PENDING) &&
  		 !irqd_irq_disabled(&desc->irq_data));
ac0e0447b   Stephen Rothwell   genirq: fix CONFI...
781
  out_eoi:
0521c8fbb   Thomas Gleixner   genirq: Provide e...
782
783
784
785
  	chip->irq_eoi(&desc->irq_data);
  	raw_spin_unlock(&desc->lock);
  }
  #endif
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
786
  /**
24b26d421   Liuweni   irq: Fix docbook ...
787
   *	handle_percpu_irq - Per CPU local irq handler
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
788
   *	@desc:	the interrupt description structure for this irq
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
789
790
791
   *
   *	Per CPU interrupts on SMP machines without locking requirements
   */
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
792
  void handle_percpu_irq(struct irq_desc *desc)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
793
  {
35e857cbe   Thomas Gleixner   genirq: Fixup cor...
794
  	struct irq_chip *chip = irq_desc_get_chip(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
795

b51bf95c5   Jiang Liu   genirq: Remove th...
796
  	kstat_incr_irqs_this_cpu(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
797

849f061c2   Thomas Gleixner   genirq: Use handl...
798
799
  	if (chip->irq_ack)
  		chip->irq_ack(&desc->irq_data);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
800

71f64340f   Huang Shijie   genirq: Remove th...
801
  	handle_irq_event_percpu(desc);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
802

849f061c2   Thomas Gleixner   genirq: Use handl...
803
804
  	if (chip->irq_eoi)
  		chip->irq_eoi(&desc->irq_data);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
805
  }
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
806
807
  /**
   * handle_percpu_devid_irq - Per CPU local irq handler with per cpu dev ids
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
808
809
810
811
812
813
814
815
816
   * @desc:	the interrupt description structure for this irq
   *
   * Per CPU interrupts on SMP machines without locking requirements. Same as
   * handle_percpu_irq() above but with the following extras:
   *
   * action->percpu_dev_id is a pointer to percpu variables which
   * contain the real device id for the cpu on which this handler is
   * called
   */
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
817
  void handle_percpu_devid_irq(struct irq_desc *desc)
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
818
819
820
  {
  	struct irq_chip *chip = irq_desc_get_chip(desc);
  	struct irqaction *action = desc->action;
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
821
  	unsigned int irq = irq_desc_get_irq(desc);
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
822
  	irqreturn_t res;
b51bf95c5   Jiang Liu   genirq: Remove th...
823
  	kstat_incr_irqs_this_cpu(desc);
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
824
825
826
  
  	if (chip->irq_ack)
  		chip->irq_ack(&desc->irq_data);
fc590c22f   Thomas Gleixner   genirq: Robustify...
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  	if (likely(action)) {
  		trace_irq_handler_entry(irq, action);
  		res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));
  		trace_irq_handler_exit(irq, action, res);
  	} else {
  		unsigned int cpu = smp_processor_id();
  		bool enabled = cpumask_test_cpu(cpu, desc->percpu_enabled);
  
  		if (enabled)
  			irq_percpu_disable(desc, cpu);
  
  		pr_err_once("Spurious%s percpu IRQ%u on CPU%u
  ",
  			    enabled ? " and unmasked" : "", irq, cpu);
  	}
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
842
843
844
845
  
  	if (chip->irq_eoi)
  		chip->irq_eoi(&desc->irq_data);
  }
b8129a1f6   Wei Yongjun   genirq: Make func...
846
  static void
3b0f95be1   Russell King   irq: Add irq_set_...
847
848
  __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
  		     int is_chained, const char *name)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
849
  {
091738a26   Thomas Gleixner   genirq: Remove re...
850
  	if (!handle) {
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
851
  		handle = handle_bad_irq;
091738a26   Thomas Gleixner   genirq: Remove re...
852
  	} else {
f86eff222   Marc Zyngier   genirq: Work arou...
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
  		struct irq_data *irq_data = &desc->irq_data;
  #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
  		/*
  		 * With hierarchical domains we might run into a
  		 * situation where the outermost chip is not yet set
  		 * up, but the inner chips are there.  Instead of
  		 * bailing we install the handler, but obviously we
  		 * cannot enable/startup the interrupt at this point.
  		 */
  		while (irq_data) {
  			if (irq_data->chip != &no_irq_chip)
  				break;
  			/*
  			 * Bail out if the outer chip is not set up
  			 * and the interrrupt supposed to be started
  			 * right away.
  			 */
  			if (WARN_ON(is_chained))
3b0f95be1   Russell King   irq: Add irq_set_...
871
  				return;
f86eff222   Marc Zyngier   genirq: Work arou...
872
873
874
875
876
  			/* Try the parent */
  			irq_data = irq_data->parent_data;
  		}
  #endif
  		if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
3b0f95be1   Russell King   irq: Add irq_set_...
877
  			return;
f8b5473fc   Thomas Gleixner   [ARM] 3690/1: gen...
878
  	}
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
879

dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
880
881
  	/* Uninstall? */
  	if (handle == handle_bad_irq) {
6b8ff3120   Thomas Gleixner   genirq: Convert c...
882
  		if (desc->irq_data.chip != &no_irq_chip)
9205e31d1   Thomas Gleixner   genirq: Provide c...
883
  			mask_ack_irq(desc);
801a0e9ae   Thomas Gleixner   genirq: Add irq d...
884
  		irq_state_set_disabled(desc);
e509bd7da   Mika Westerberg   genirq: Allow mig...
885
886
  		if (is_chained)
  			desc->action = NULL;
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
887
888
889
  		desc->depth = 1;
  	}
  	desc->handle_irq = handle;
a460e745e   Ingo Molnar   [PATCH] genirq: c...
890
  	desc->name = name;
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
891
892
  
  	if (handle != handle_bad_irq && is_chained) {
1984e0759   Marc Zyngier   genirq: Skip chai...
893
  		unsigned int type = irqd_get_trigger_type(&desc->irq_data);
1e12c4a93   Marc Zyngier   genirq: Correctly...
894
895
896
897
898
899
900
901
  		/*
  		 * We're about to start this interrupt immediately,
  		 * hence the need to set the trigger configuration.
  		 * But the .set_type callback may have overridden the
  		 * flow handler, ignoring that we're dealing with a
  		 * chained interrupt. Reset it immediately because we
  		 * do know better.
  		 */
1984e0759   Marc Zyngier   genirq: Skip chai...
902
903
904
905
  		if (type != IRQ_TYPE_NONE) {
  			__irq_set_trigger(desc, type);
  			desc->handle_irq = handle;
  		}
1e12c4a93   Marc Zyngier   genirq: Correctly...
906

1ccb4e612   Thomas Gleixner   genirq: Wrap the ...
907
908
  		irq_settings_set_noprobe(desc);
  		irq_settings_set_norequest(desc);
7f1b1244e   Paul Mundt   genirq: Support p...
909
  		irq_settings_set_nothread(desc);
e509bd7da   Mika Westerberg   genirq: Allow mig...
910
  		desc->action = &chained_action;
4cde9c6b8   Thomas Gleixner   genirq: Add force...
911
  		irq_startup(desc, IRQ_RESEND, IRQ_START_FORCE);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
912
  	}
3b0f95be1   Russell King   irq: Add irq_set_...
913
914
915
916
917
918
919
920
921
922
923
924
925
  }
  
  void
  __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
  		  const char *name)
  {
  	unsigned long flags;
  	struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
  
  	if (!desc)
  		return;
  
  	__irq_do_set_handler(desc, handle, is_chained, name);
02725e747   Thomas Gleixner   genirq: Use irq_g...
926
  	irq_put_desc_busunlock(desc, flags);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
927
  }
3836ca08a   Thomas Gleixner   genirq: Consolida...
928
  EXPORT_SYMBOL_GPL(__irq_set_handler);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
929
930
  
  void
3b0f95be1   Russell King   irq: Add irq_set_...
931
932
933
934
935
936
937
938
  irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle,
  				 void *data)
  {
  	unsigned long flags;
  	struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
  
  	if (!desc)
  		return;
af7080e04   Jiang Liu   genirq: Move fiel...
939
  	desc->irq_common_data.handler_data = data;
2c4569ca2   Thomas Gleixner   genirq: Fix chain...
940
  	__irq_do_set_handler(desc, handle, 1, NULL);
3b0f95be1   Russell King   irq: Add irq_set_...
941
942
943
944
945
946
  
  	irq_put_desc_busunlock(desc, flags);
  }
  EXPORT_SYMBOL_GPL(irq_set_chained_handler_and_data);
  
  void
3836ca08a   Thomas Gleixner   genirq: Consolida...
947
  irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
a460e745e   Ingo Molnar   [PATCH] genirq: c...
948
  			      irq_flow_handler_t handle, const char *name)
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
949
  {
35e857cbe   Thomas Gleixner   genirq: Fixup cor...
950
  	irq_set_chip(irq, chip);
3836ca08a   Thomas Gleixner   genirq: Consolida...
951
  	__irq_set_handler(irq, handle, 0, name);
dd87eb3a2   Thomas Gleixner   [PATCH] genirq: a...
952
  }
b3ae66f20   Kuninori Morimoto   genirq: Export ir...
953
  EXPORT_SYMBOL_GPL(irq_set_chip_and_handler_name);
46f4f8f66   Ralf Baechle   IRQ_NOPROBE helpe...
954

442471848   Thomas Gleixner   genirq: Provide s...
955
  void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
46f4f8f66   Ralf Baechle   IRQ_NOPROBE helpe...
956
  {
e8f241893   Marc Zyngier   genirq: Restore t...
957
  	unsigned long flags, trigger, tmp;
31d9d9b6d   Marc Zyngier   genirq: Add suppo...
958
  	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
46f4f8f66   Ralf Baechle   IRQ_NOPROBE helpe...
959

442471848   Thomas Gleixner   genirq: Provide s...
960
  	if (!desc)
46f4f8f66   Ralf Baechle   IRQ_NOPROBE helpe...
961
  		return;
04c848d39   Thomas Gleixner   genirq: Warn when...
962
963
964
965
966
967
  
  	/*
  	 * Warn when a driver sets the no autoenable flag on an already
  	 * active interrupt.
  	 */
  	WARN_ON_ONCE(!desc->depth && (set & _IRQ_NOAUTOEN));
a005677b3   Thomas Gleixner   genirq: Mirror IR...
968
  	irq_settings_clr_and_set(desc, clr, set);
e8f241893   Marc Zyngier   genirq: Restore t...
969
  	trigger = irqd_get_trigger_type(&desc->irq_data);
876dbd4cc   Thomas Gleixner   genirq: Mirror ir...
970
  	irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
e1ef82414   Thomas Gleixner   genirq: Reflect I...
971
  		   IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
a005677b3   Thomas Gleixner   genirq: Mirror IR...
972
973
974
975
  	if (irq_settings_has_no_balance_set(desc))
  		irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
  	if (irq_settings_is_per_cpu(desc))
  		irqd_set(&desc->irq_data, IRQD_PER_CPU);
e1ef82414   Thomas Gleixner   genirq: Reflect I...
976
977
  	if (irq_settings_can_move_pcntxt(desc))
  		irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT);
0ef5ca1e1   Thomas Gleixner   genirq; Fix clean...
978
979
  	if (irq_settings_is_level(desc))
  		irqd_set(&desc->irq_data, IRQD_LEVEL);
a005677b3   Thomas Gleixner   genirq: Mirror IR...
980

e8f241893   Marc Zyngier   genirq: Restore t...
981
982
983
984
985
  	tmp = irq_settings_get_trigger_mask(desc);
  	if (tmp != IRQ_TYPE_NONE)
  		trigger = tmp;
  
  	irqd_set(&desc->irq_data, trigger);
876dbd4cc   Thomas Gleixner   genirq: Mirror ir...
986

02725e747   Thomas Gleixner   genirq: Use irq_g...
987
  	irq_put_desc_unlock(desc, flags);
46f4f8f66   Ralf Baechle   IRQ_NOPROBE helpe...
988
  }
edf76f830   Jonathan Cameron   irq: Export funct...
989
  EXPORT_SYMBOL_GPL(irq_modify_status);
0fdb4b259   David Daney   genirq: Add chip ...
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  
  /**
   *	irq_cpu_online - Invoke all irq_cpu_online functions.
   *
   *	Iterate through all irqs and invoke the chip.irq_cpu_online()
   *	for each.
   */
  void irq_cpu_online(void)
  {
  	struct irq_desc *desc;
  	struct irq_chip *chip;
  	unsigned long flags;
  	unsigned int irq;
  
  	for_each_active_irq(irq) {
  		desc = irq_to_desc(irq);
  		if (!desc)
  			continue;
  
  		raw_spin_lock_irqsave(&desc->lock, flags);
  
  		chip = irq_data_get_irq_chip(&desc->irq_data);
b3d422329   Thomas Gleixner   genirq: Add chip ...
1012
1013
  		if (chip && chip->irq_cpu_online &&
  		    (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) ||
32f4125eb   Thomas Gleixner   genirq: Move INPR...
1014
  		     !irqd_irq_disabled(&desc->irq_data)))
0fdb4b259   David Daney   genirq: Add chip ...
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
  			chip->irq_cpu_online(&desc->irq_data);
  
  		raw_spin_unlock_irqrestore(&desc->lock, flags);
  	}
  }
  
  /**
   *	irq_cpu_offline - Invoke all irq_cpu_offline functions.
   *
   *	Iterate through all irqs and invoke the chip.irq_cpu_offline()
   *	for each.
   */
  void irq_cpu_offline(void)
  {
  	struct irq_desc *desc;
  	struct irq_chip *chip;
  	unsigned long flags;
  	unsigned int irq;
  
  	for_each_active_irq(irq) {
  		desc = irq_to_desc(irq);
  		if (!desc)
  			continue;
  
  		raw_spin_lock_irqsave(&desc->lock, flags);
  
  		chip = irq_data_get_irq_chip(&desc->irq_data);
b3d422329   Thomas Gleixner   genirq: Add chip ...
1042
1043
  		if (chip && chip->irq_cpu_offline &&
  		    (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) ||
32f4125eb   Thomas Gleixner   genirq: Move INPR...
1044
  		     !irqd_irq_disabled(&desc->irq_data)))
0fdb4b259   David Daney   genirq: Add chip ...
1045
1046
1047
1048
1049
  			chip->irq_cpu_offline(&desc->irq_data);
  
  		raw_spin_unlock_irqrestore(&desc->lock, flags);
  	}
  }
85f08c17d   Jiang Liu   genirq: Introduce...
1050
1051
  
  #ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
7703b08cc   David Daney   genirq: Add handl...
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
  
  #ifdef CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS
  /**
   *	handle_fasteoi_ack_irq - irq handler for edge hierarchy
   *	stacked on transparent controllers
   *
   *	@desc:	the interrupt description structure for this irq
   *
   *	Like handle_fasteoi_irq(), but for use with hierarchy where
   *	the irq_chip also needs to have its ->irq_ack() function
   *	called.
   */
  void handle_fasteoi_ack_irq(struct irq_desc *desc)
  {
  	struct irq_chip *chip = desc->irq_data.chip;
  
  	raw_spin_lock(&desc->lock);
  
  	if (!irq_may_run(desc))
  		goto out;
  
  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
  
  	/*
  	 * If its disabled or no action available
  	 * then mask it and get out of here:
  	 */
  	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
  		desc->istate |= IRQS_PENDING;
  		mask_irq(desc);
  		goto out;
  	}
  
  	kstat_incr_irqs_this_cpu(desc);
  	if (desc->istate & IRQS_ONESHOT)
  		mask_irq(desc);
  
  	/* Start handling the irq */
  	desc->irq_data.chip->irq_ack(&desc->irq_data);
  
  	preflow_handler(desc);
  	handle_irq_event(desc);
  
  	cond_unmask_eoi_irq(desc, chip);
  
  	raw_spin_unlock(&desc->lock);
  	return;
  out:
  	if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
  		chip->irq_eoi(&desc->irq_data);
  	raw_spin_unlock(&desc->lock);
  }
  EXPORT_SYMBOL_GPL(handle_fasteoi_ack_irq);
  
  /**
   *	handle_fasteoi_mask_irq - irq handler for level hierarchy
   *	stacked on transparent controllers
   *
   *	@desc:	the interrupt description structure for this irq
   *
   *	Like handle_fasteoi_irq(), but for use with hierarchy where
   *	the irq_chip also needs to have its ->irq_mask_ack() function
   *	called.
   */
  void handle_fasteoi_mask_irq(struct irq_desc *desc)
  {
  	struct irq_chip *chip = desc->irq_data.chip;
  
  	raw_spin_lock(&desc->lock);
  	mask_ack_irq(desc);
  
  	if (!irq_may_run(desc))
  		goto out;
  
  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
  
  	/*
  	 * If its disabled or no action available
  	 * then mask it and get out of here:
  	 */
  	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
  		desc->istate |= IRQS_PENDING;
  		mask_irq(desc);
  		goto out;
  	}
  
  	kstat_incr_irqs_this_cpu(desc);
  	if (desc->istate & IRQS_ONESHOT)
  		mask_irq(desc);
  
  	preflow_handler(desc);
  	handle_irq_event(desc);
  
  	cond_unmask_eoi_irq(desc, chip);
  
  	raw_spin_unlock(&desc->lock);
  	return;
  out:
  	if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
  		chip->irq_eoi(&desc->irq_data);
  	raw_spin_unlock(&desc->lock);
  }
  EXPORT_SYMBOL_GPL(handle_fasteoi_mask_irq);
  
  #endif /* CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS */
85f08c17d   Jiang Liu   genirq: Introduce...
1157
  /**
3cfeffc26   Stefan Agner   genirq: Add irq_c...
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
   * irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if
   * NULL)
   * @data:	Pointer to interrupt specific data
   */
  void irq_chip_enable_parent(struct irq_data *data)
  {
  	data = data->parent_data;
  	if (data->chip->irq_enable)
  		data->chip->irq_enable(data);
  	else
  		data->chip->irq_unmask(data);
  }
65efd9a49   David Daney   genirq: Export mo...
1170
  EXPORT_SYMBOL_GPL(irq_chip_enable_parent);
3cfeffc26   Stefan Agner   genirq: Add irq_c...
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
  
  /**
   * irq_chip_disable_parent - Disable the parent interrupt (defaults to mask if
   * NULL)
   * @data:	Pointer to interrupt specific data
   */
  void irq_chip_disable_parent(struct irq_data *data)
  {
  	data = data->parent_data;
  	if (data->chip->irq_disable)
  		data->chip->irq_disable(data);
  	else
  		data->chip->irq_mask(data);
  }
65efd9a49   David Daney   genirq: Export mo...
1185
  EXPORT_SYMBOL_GPL(irq_chip_disable_parent);
3cfeffc26   Stefan Agner   genirq: Add irq_c...
1186
1187
  
  /**
85f08c17d   Jiang Liu   genirq: Introduce...
1188
1189
1190
1191
1192
1193
1194
1195
   * irq_chip_ack_parent - Acknowledge the parent interrupt
   * @data:	Pointer to interrupt specific data
   */
  void irq_chip_ack_parent(struct irq_data *data)
  {
  	data = data->parent_data;
  	data->chip->irq_ack(data);
  }
a4289dc2e   Jake Oshins   genirq/msi: Expor...
1196
  EXPORT_SYMBOL_GPL(irq_chip_ack_parent);
85f08c17d   Jiang Liu   genirq: Introduce...
1197
1198
  
  /**
56e8abab6   Yingjoe Chen   genirq: Add more ...
1199
1200
1201
1202
1203
1204
1205
1206
   * irq_chip_mask_parent - Mask the parent interrupt
   * @data:	Pointer to interrupt specific data
   */
  void irq_chip_mask_parent(struct irq_data *data)
  {
  	data = data->parent_data;
  	data->chip->irq_mask(data);
  }
52b2a05fa   Quan Nguyen   genirq: Export IR...
1207
  EXPORT_SYMBOL_GPL(irq_chip_mask_parent);
56e8abab6   Yingjoe Chen   genirq: Add more ...
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
  
  /**
   * irq_chip_unmask_parent - Unmask the parent interrupt
   * @data:	Pointer to interrupt specific data
   */
  void irq_chip_unmask_parent(struct irq_data *data)
  {
  	data = data->parent_data;
  	data->chip->irq_unmask(data);
  }
52b2a05fa   Quan Nguyen   genirq: Export IR...
1218
  EXPORT_SYMBOL_GPL(irq_chip_unmask_parent);
56e8abab6   Yingjoe Chen   genirq: Add more ...
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
  
  /**
   * irq_chip_eoi_parent - Invoke EOI on the parent interrupt
   * @data:	Pointer to interrupt specific data
   */
  void irq_chip_eoi_parent(struct irq_data *data)
  {
  	data = data->parent_data;
  	data->chip->irq_eoi(data);
  }
52b2a05fa   Quan Nguyen   genirq: Export IR...
1229
  EXPORT_SYMBOL_GPL(irq_chip_eoi_parent);
56e8abab6   Yingjoe Chen   genirq: Add more ...
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
  
  /**
   * irq_chip_set_affinity_parent - Set affinity on the parent interrupt
   * @data:	Pointer to interrupt specific data
   * @dest:	The affinity mask to set
   * @force:	Flag to enforce setting (disable online checks)
   *
   * Conditinal, as the underlying parent chip might not implement it.
   */
  int irq_chip_set_affinity_parent(struct irq_data *data,
  				 const struct cpumask *dest, bool force)
  {
  	data = data->parent_data;
  	if (data->chip->irq_set_affinity)
  		return data->chip->irq_set_affinity(data, dest, force);
b7560de19   Grygorii Strashko   genirq: Introduce...
1245
1246
1247
  
  	return -ENOSYS;
  }
65efd9a49   David Daney   genirq: Export mo...
1248
  EXPORT_SYMBOL_GPL(irq_chip_set_affinity_parent);
b7560de19   Grygorii Strashko   genirq: Introduce...
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
  
  /**
   * irq_chip_set_type_parent - Set IRQ type on the parent interrupt
   * @data:	Pointer to interrupt specific data
   * @type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
   *
   * Conditional, as the underlying parent chip might not implement it.
   */
  int irq_chip_set_type_parent(struct irq_data *data, unsigned int type)
  {
  	data = data->parent_data;
  
  	if (data->chip->irq_set_type)
  		return data->chip->irq_set_type(data, type);
56e8abab6   Yingjoe Chen   genirq: Add more ...
1263
1264
1265
  
  	return -ENOSYS;
  }
52b2a05fa   Quan Nguyen   genirq: Export IR...
1266
  EXPORT_SYMBOL_GPL(irq_chip_set_type_parent);
56e8abab6   Yingjoe Chen   genirq: Add more ...
1267
1268
  
  /**
85f08c17d   Jiang Liu   genirq: Introduce...
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
   * irq_chip_retrigger_hierarchy - Retrigger an interrupt in hardware
   * @data:	Pointer to interrupt specific data
   *
   * Iterate through the domain hierarchy of the interrupt and check
   * whether a hw retrigger function exists. If yes, invoke it.
   */
  int irq_chip_retrigger_hierarchy(struct irq_data *data)
  {
  	for (data = data->parent_data; data; data = data->parent_data)
  		if (data->chip && data->chip->irq_retrigger)
  			return data->chip->irq_retrigger(data);
6d4affea7   Grygorii Strashko   genirq: Don't ret...
1280
  	return 0;
85f08c17d   Jiang Liu   genirq: Introduce...
1281
  }
08b55e2a9   Marc Zyngier   genirq: Add irqch...
1282
1283
  
  /**
0a4377de3   Jiang Liu   genirq: Introduce...
1284
1285
   * irq_chip_set_vcpu_affinity_parent - Set vcpu affinity on the parent interrupt
   * @data:	Pointer to interrupt specific data
8505a81bb   Masanari Iida   genirq: Use the p...
1286
   * @vcpu_info:	The vcpu affinity information
0a4377de3   Jiang Liu   genirq: Introduce...
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
   */
  int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, void *vcpu_info)
  {
  	data = data->parent_data;
  	if (data->chip->irq_set_vcpu_affinity)
  		return data->chip->irq_set_vcpu_affinity(data, vcpu_info);
  
  	return -ENOSYS;
  }
  
  /**
08b55e2a9   Marc Zyngier   genirq: Add irqch...
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
   * irq_chip_set_wake_parent - Set/reset wake-up on the parent interrupt
   * @data:	Pointer to interrupt specific data
   * @on:		Whether to set or reset the wake-up capability of this irq
   *
   * Conditional, as the underlying parent chip might not implement it.
   */
  int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on)
  {
  	data = data->parent_data;
  	if (data->chip->irq_set_wake)
  		return data->chip->irq_set_wake(data, on);
  
  	return -ENOSYS;
  }
85f08c17d   Jiang Liu   genirq: Introduce...
1312
  #endif
515085ef7   Jiang Liu   genirq: Introduce...
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
  
  /**
   * irq_chip_compose_msi_msg - Componse msi message for a irq chip
   * @data:	Pointer to interrupt specific data
   * @msg:	Pointer to the MSI message
   *
   * For hierarchical domains we find the first chip in the hierarchy
   * which implements the irq_compose_msi_msg callback. For non
   * hierarchical we use the top level chip.
   */
  int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
  {
  	struct irq_data *pos = NULL;
  
  #ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
  	for (; data; data = data->parent_data)
  #endif
  		if (data->chip && data->chip->irq_compose_msi_msg)
  			pos = data;
  	if (!pos)
  		return -ENOSYS;
  
  	pos->chip->irq_compose_msi_msg(pos, msg);
  
  	return 0;
  }
be45beb2d   Jon Hunter   genirq: Add runti...
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
  
  /**
   * irq_chip_pm_get - Enable power for an IRQ chip
   * @data:	Pointer to interrupt specific data
   *
   * Enable the power to the IRQ chip referenced by the interrupt data
   * structure.
   */
  int irq_chip_pm_get(struct irq_data *data)
  {
  	int retval;
  
  	if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device) {
  		retval = pm_runtime_get_sync(data->chip->parent_device);
  		if (retval < 0) {
  			pm_runtime_put_noidle(data->chip->parent_device);
  			return retval;
  		}
  	}
  
  	return 0;
  }
  
  /**
   * irq_chip_pm_put - Disable power for an IRQ chip
   * @data:	Pointer to interrupt specific data
   *
   * Disable the power to the IRQ chip referenced by the interrupt data
   * structure, belongs. Note that power will only be disabled, once this
   * function has been called for all IRQs that have called irq_chip_pm_get().
   */
  int irq_chip_pm_put(struct irq_data *data)
  {
  	int retval = 0;
  
  	if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device)
  		retval = pm_runtime_put(data->chip->parent_device);
  
  	return (retval < 0) ? retval : 0;
  }