Blame view

kernel/irq/generic-chip.c 15.7 KB
7d8280624   Thomas Gleixner   genirq: Implement...
1
2
3
4
5
6
7
8
  /*
   * Library implementing the most common irq chip callback functions
   *
   * Copyright (C) 2011, Thomas Gleixner
   */
  #include <linux/io.h>
  #include <linux/irq.h>
  #include <linux/slab.h>
6e5fdeedc   Paul Gortmaker   kernel: Fix files...
9
  #include <linux/export.h>
088f40b7b   Thomas Gleixner   genirq: Generic c...
10
  #include <linux/irqdomain.h>
7d8280624   Thomas Gleixner   genirq: Implement...
11
12
  #include <linux/interrupt.h>
  #include <linux/kernel_stat.h>
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
13
  #include <linux/syscore_ops.h>
7d8280624   Thomas Gleixner   genirq: Implement...
14
15
  
  #include "internals.h"
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
16
17
  static LIST_HEAD(gc_list);
  static DEFINE_RAW_SPINLOCK(gc_lock);
7d8280624   Thomas Gleixner   genirq: Implement...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  /**
   * irq_gc_noop - NOOP function
   * @d: irq_data
   */
  void irq_gc_noop(struct irq_data *d)
  {
  }
  
  /**
   * irq_gc_mask_disable_reg - Mask chip via disable register
   * @d: irq_data
   *
   * Chip has separate enable/disable registers instead of a single mask
   * register.
   */
  void irq_gc_mask_disable_reg(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
cfeaa93f8   Gerlando Falauto   genirq: Generic c...
36
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
966dc736b   Thomas Gleixner   genirq: Generic c...
37
  	u32 mask = d->mask;
7d8280624   Thomas Gleixner   genirq: Implement...
38
39
  
  	irq_gc_lock(gc);
332fd7c4f   Kevin Cernekee   genirq: Generic c...
40
  	irq_reg_writel(gc, mask, ct->regs.disable);
899f0e66f   Gerlando Falauto   genirq: Generic c...
41
  	*ct->mask_cache &= ~mask;
7d8280624   Thomas Gleixner   genirq: Implement...
42
43
44
45
  	irq_gc_unlock(gc);
  }
  
  /**
ccc414f83   Thomas Gleixner   genirq: Add the g...
46
   * irq_gc_mask_set_bit - Mask chip via setting bit in mask register
7d8280624   Thomas Gleixner   genirq: Implement...
47
48
49
50
51
52
53
54
   * @d: irq_data
   *
   * Chip has a single mask register. Values of this register are cached
   * and protected by gc->lock
   */
  void irq_gc_mask_set_bit(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
cfeaa93f8   Gerlando Falauto   genirq: Generic c...
55
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
966dc736b   Thomas Gleixner   genirq: Generic c...
56
  	u32 mask = d->mask;
7d8280624   Thomas Gleixner   genirq: Implement...
57
58
  
  	irq_gc_lock(gc);
899f0e66f   Gerlando Falauto   genirq: Generic c...
59
  	*ct->mask_cache |= mask;
332fd7c4f   Kevin Cernekee   genirq: Generic c...
60
  	irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
7d8280624   Thomas Gleixner   genirq: Implement...
61
62
  	irq_gc_unlock(gc);
  }
d55f0cc4c   Fabio Estevam   genirq: generic-c...
63
  EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit);
7d8280624   Thomas Gleixner   genirq: Implement...
64
65
  
  /**
ccc414f83   Thomas Gleixner   genirq: Add the g...
66
   * irq_gc_mask_clr_bit - Mask chip via clearing bit in mask register
7d8280624   Thomas Gleixner   genirq: Implement...
67
68
69
70
71
72
73
74
   * @d: irq_data
   *
   * Chip has a single mask register. Values of this register are cached
   * and protected by gc->lock
   */
  void irq_gc_mask_clr_bit(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
cfeaa93f8   Gerlando Falauto   genirq: Generic c...
75
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
966dc736b   Thomas Gleixner   genirq: Generic c...
76
  	u32 mask = d->mask;
7d8280624   Thomas Gleixner   genirq: Implement...
77
78
  
  	irq_gc_lock(gc);
899f0e66f   Gerlando Falauto   genirq: Generic c...
79
  	*ct->mask_cache &= ~mask;
332fd7c4f   Kevin Cernekee   genirq: Generic c...
80
  	irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
7d8280624   Thomas Gleixner   genirq: Implement...
81
82
  	irq_gc_unlock(gc);
  }
d55f0cc4c   Fabio Estevam   genirq: generic-c...
83
  EXPORT_SYMBOL_GPL(irq_gc_mask_clr_bit);
7d8280624   Thomas Gleixner   genirq: Implement...
84
85
86
87
88
89
90
91
92
93
94
  
  /**
   * irq_gc_unmask_enable_reg - Unmask chip via enable register
   * @d: irq_data
   *
   * Chip has separate enable/disable registers instead of a single mask
   * register.
   */
  void irq_gc_unmask_enable_reg(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
cfeaa93f8   Gerlando Falauto   genirq: Generic c...
95
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
966dc736b   Thomas Gleixner   genirq: Generic c...
96
  	u32 mask = d->mask;
7d8280624   Thomas Gleixner   genirq: Implement...
97
98
  
  	irq_gc_lock(gc);
332fd7c4f   Kevin Cernekee   genirq: Generic c...
99
  	irq_reg_writel(gc, mask, ct->regs.enable);
899f0e66f   Gerlando Falauto   genirq: Generic c...
100
  	*ct->mask_cache |= mask;
7d8280624   Thomas Gleixner   genirq: Implement...
101
102
103
104
  	irq_gc_unlock(gc);
  }
  
  /**
659fb32d1   Simon Guinot   genirq: replace i...
105
   * irq_gc_ack_set_bit - Ack pending interrupt via setting bit
7d8280624   Thomas Gleixner   genirq: Implement...
106
107
   * @d: irq_data
   */
659fb32d1   Simon Guinot   genirq: replace i...
108
  void irq_gc_ack_set_bit(struct irq_data *d)
7d8280624   Thomas Gleixner   genirq: Implement...
109
110
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
cfeaa93f8   Gerlando Falauto   genirq: Generic c...
111
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
966dc736b   Thomas Gleixner   genirq: Generic c...
112
  	u32 mask = d->mask;
7d8280624   Thomas Gleixner   genirq: Implement...
113
114
  
  	irq_gc_lock(gc);
332fd7c4f   Kevin Cernekee   genirq: Generic c...
115
  	irq_reg_writel(gc, mask, ct->regs.ack);
7d8280624   Thomas Gleixner   genirq: Implement...
116
117
  	irq_gc_unlock(gc);
  }
d55f0cc4c   Fabio Estevam   genirq: generic-c...
118
  EXPORT_SYMBOL_GPL(irq_gc_ack_set_bit);
7d8280624   Thomas Gleixner   genirq: Implement...
119
120
  
  /**
659fb32d1   Simon Guinot   genirq: replace i...
121
122
123
124
125
126
   * irq_gc_ack_clr_bit - Ack pending interrupt via clearing bit
   * @d: irq_data
   */
  void irq_gc_ack_clr_bit(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
cfeaa93f8   Gerlando Falauto   genirq: Generic c...
127
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
966dc736b   Thomas Gleixner   genirq: Generic c...
128
  	u32 mask = ~d->mask;
659fb32d1   Simon Guinot   genirq: replace i...
129
130
  
  	irq_gc_lock(gc);
332fd7c4f   Kevin Cernekee   genirq: Generic c...
131
  	irq_reg_writel(gc, mask, ct->regs.ack);
659fb32d1   Simon Guinot   genirq: replace i...
132
133
134
135
  	irq_gc_unlock(gc);
  }
  
  /**
37074c5a1   Uwe Kleine-König   irq/generic-chip:...
136
   * irq_gc_mask_disable_reg_and_ack - Mask and ack pending interrupt
7d8280624   Thomas Gleixner   genirq: Implement...
137
138
139
140
141
   * @d: irq_data
   */
  void irq_gc_mask_disable_reg_and_ack(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
cfeaa93f8   Gerlando Falauto   genirq: Generic c...
142
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
966dc736b   Thomas Gleixner   genirq: Generic c...
143
  	u32 mask = d->mask;
7d8280624   Thomas Gleixner   genirq: Implement...
144
145
  
  	irq_gc_lock(gc);
332fd7c4f   Kevin Cernekee   genirq: Generic c...
146
147
  	irq_reg_writel(gc, mask, ct->regs.mask);
  	irq_reg_writel(gc, mask, ct->regs.ack);
7d8280624   Thomas Gleixner   genirq: Implement...
148
149
150
151
152
153
154
155
156
157
  	irq_gc_unlock(gc);
  }
  
  /**
   * irq_gc_eoi - EOI interrupt
   * @d: irq_data
   */
  void irq_gc_eoi(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
cfeaa93f8   Gerlando Falauto   genirq: Generic c...
158
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
966dc736b   Thomas Gleixner   genirq: Generic c...
159
  	u32 mask = d->mask;
7d8280624   Thomas Gleixner   genirq: Implement...
160
161
  
  	irq_gc_lock(gc);
332fd7c4f   Kevin Cernekee   genirq: Generic c...
162
  	irq_reg_writel(gc, mask, ct->regs.eoi);
7d8280624   Thomas Gleixner   genirq: Implement...
163
164
165
166
167
  	irq_gc_unlock(gc);
  }
  
  /**
   * irq_gc_set_wake - Set/clr wake bit for an interrupt
ccc414f83   Thomas Gleixner   genirq: Add the g...
168
169
   * @d:  irq_data
   * @on: Indicates whether the wake bit should be set or cleared
7d8280624   Thomas Gleixner   genirq: Implement...
170
171
172
173
174
175
176
177
   *
   * For chips where the wake from suspend functionality is not
   * configured in a separate register and the wakeup active state is
   * just stored in a bitmask.
   */
  int irq_gc_set_wake(struct irq_data *d, unsigned int on)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
966dc736b   Thomas Gleixner   genirq: Generic c...
178
  	u32 mask = d->mask;
7d8280624   Thomas Gleixner   genirq: Implement...
179
180
181
182
183
184
185
186
187
188
189
190
  
  	if (!(mask & gc->wake_enabled))
  		return -EINVAL;
  
  	irq_gc_lock(gc);
  	if (on)
  		gc->wake_active |= mask;
  	else
  		gc->wake_active &= ~mask;
  	irq_gc_unlock(gc);
  	return 0;
  }
b79055952   Kevin Cernekee   genirq: Generic c...
191
192
193
194
195
196
197
198
199
  static u32 irq_readl_be(void __iomem *addr)
  {
  	return ioread32be(addr);
  }
  
  static void irq_writel_be(u32 val, void __iomem *addr)
  {
  	iowrite32be(val, addr);
  }
3528d82b6   Thomas Gleixner   genirq: Generic c...
200
201
202
203
204
205
206
207
208
209
210
211
  static void
  irq_init_generic_chip(struct irq_chip_generic *gc, const char *name,
  		      int num_ct, unsigned int irq_base,
  		      void __iomem *reg_base, irq_flow_handler_t handler)
  {
  	raw_spin_lock_init(&gc->lock);
  	gc->num_ct = num_ct;
  	gc->irq_base = irq_base;
  	gc->reg_base = reg_base;
  	gc->chip_types->chip.name = name;
  	gc->chip_types->handler = handler;
  }
7d8280624   Thomas Gleixner   genirq: Implement...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  /**
   * irq_alloc_generic_chip - Allocate a generic chip and initialize it
   * @name:	Name of the irq chip
   * @num_ct:	Number of irq_chip_type instances associated with this
   * @irq_base:	Interrupt base nr for this chip
   * @reg_base:	Register base address (virtual)
   * @handler:	Default flow handler associated with this chip
   *
   * Returns an initialized irq_chip_generic structure. The chip defaults
   * to the primary (index 0) irq_chip_type and @handler
   */
  struct irq_chip_generic *
  irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base,
  		       void __iomem *reg_base, irq_flow_handler_t handler)
  {
  	struct irq_chip_generic *gc;
  	unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type);
  
  	gc = kzalloc(sz, GFP_KERNEL);
  	if (gc) {
3528d82b6   Thomas Gleixner   genirq: Generic c...
232
233
  		irq_init_generic_chip(gc, name, num_ct, irq_base, reg_base,
  				      handler);
7d8280624   Thomas Gleixner   genirq: Implement...
234
235
236
  	}
  	return gc;
  }
825de2e90   Nobuhiro Iwamatsu   irq: Add EXPORT_S...
237
  EXPORT_SYMBOL_GPL(irq_alloc_generic_chip);
7d8280624   Thomas Gleixner   genirq: Implement...
238

3528d82b6   Thomas Gleixner   genirq: Generic c...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  static void
  irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags)
  {
  	struct irq_chip_type *ct = gc->chip_types;
  	u32 *mskptr = &gc->mask_cache, mskreg = ct->regs.mask;
  	int i;
  
  	for (i = 0; i < gc->num_ct; i++) {
  		if (flags & IRQ_GC_MASK_CACHE_PER_TYPE) {
  			mskptr = &ct[i].mask_cache_priv;
  			mskreg = ct[i].regs.mask;
  		}
  		ct[i].mask_cache = mskptr;
  		if (flags & IRQ_GC_INIT_MASK_CACHE)
332fd7c4f   Kevin Cernekee   genirq: Generic c...
253
  			*mskptr = irq_reg_readl(gc, mskreg);
3528d82b6   Thomas Gleixner   genirq: Generic c...
254
255
  	}
  }
088f40b7b   Thomas Gleixner   genirq: Generic c...
256
  /**
f88eecfe2   Sebastian Frias   genirq/generic_ch...
257
   * __irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain
088f40b7b   Thomas Gleixner   genirq: Generic c...
258
   * @d:			irq domain for which to allocate chips
f88eecfe2   Sebastian Frias   genirq/generic_ch...
259
   * @irqs_per_chip:	Number of interrupts each chip handles (max 32)
088f40b7b   Thomas Gleixner   genirq: Generic c...
260
261
262
263
264
   * @num_ct:		Number of irq_chip_type instances associated with this
   * @name:		Name of the irq chip
   * @handler:		Default flow handler associated with these chips
   * @clr:		IRQ_* bits to clear in the mapping function
   * @set:		IRQ_* bits to set in the mapping function
6fff83140   James Hogan   genirq: Irqchip: ...
265
   * @gcflags:		Generic chip specific setup flags
088f40b7b   Thomas Gleixner   genirq: Generic c...
266
   */
f88eecfe2   Sebastian Frias   genirq/generic_ch...
267
268
269
270
271
  int __irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
  				     int num_ct, const char *name,
  				     irq_flow_handler_t handler,
  				     unsigned int clr, unsigned int set,
  				     enum irq_gc_flags gcflags)
088f40b7b   Thomas Gleixner   genirq: Generic c...
272
273
274
275
276
277
278
279
280
  {
  	struct irq_domain_chip_generic *dgc;
  	struct irq_chip_generic *gc;
  	int numchips, sz, i;
  	unsigned long flags;
  	void *tmp;
  
  	if (d->gc)
  		return -EBUSY;
505608d2b   Linus Torvalds   Merge branch 'irq...
281
  	numchips = DIV_ROUND_UP(d->revmap_size, irqs_per_chip);
088f40b7b   Thomas Gleixner   genirq: Generic c...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  	if (!numchips)
  		return -EINVAL;
  
  	/* Allocate a pointer, generic chip and chiptypes for each chip */
  	sz = sizeof(*dgc) + numchips * sizeof(gc);
  	sz += numchips * (sizeof(*gc) + num_ct * sizeof(struct irq_chip_type));
  
  	tmp = dgc = kzalloc(sz, GFP_KERNEL);
  	if (!dgc)
  		return -ENOMEM;
  	dgc->irqs_per_chip = irqs_per_chip;
  	dgc->num_chips = numchips;
  	dgc->irq_flags_to_set = set;
  	dgc->irq_flags_to_clear = clr;
  	dgc->gc_flags = gcflags;
  	d->gc = dgc;
  
  	/* Calc pointer to the first generic chip */
  	tmp += sizeof(*dgc) + numchips * sizeof(gc);
  	for (i = 0; i < numchips; i++) {
  		/* Store the pointer to the generic chip */
  		dgc->gc[i] = gc = tmp;
  		irq_init_generic_chip(gc, name, num_ct, i * irqs_per_chip,
  				      NULL, handler);
b79055952   Kevin Cernekee   genirq: Generic c...
306

088f40b7b   Thomas Gleixner   genirq: Generic c...
307
  		gc->domain = d;
b79055952   Kevin Cernekee   genirq: Generic c...
308
309
310
311
  		if (gcflags & IRQ_GC_BE_IO) {
  			gc->reg_readl = &irq_readl_be;
  			gc->reg_writel = &irq_writel_be;
  		}
088f40b7b   Thomas Gleixner   genirq: Generic c...
312
313
314
315
316
317
  		raw_spin_lock_irqsave(&gc_lock, flags);
  		list_add_tail(&gc->list, &gc_list);
  		raw_spin_unlock_irqrestore(&gc_lock, flags);
  		/* Calc pointer to the next generic chip */
  		tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type);
  	}
0bb4afb45   Grant Likely   irqdomain: Add a ...
318
  	d->name = name;
088f40b7b   Thomas Gleixner   genirq: Generic c...
319
320
  	return 0;
  }
f88eecfe2   Sebastian Frias   genirq/generic_ch...
321
  EXPORT_SYMBOL_GPL(__irq_alloc_domain_generic_chips);
088f40b7b   Thomas Gleixner   genirq: Generic c...
322

f0c450eaa   Sebastian Frias   genirq/generic_ch...
323
324
325
326
327
328
329
330
331
332
333
334
335
  static struct irq_chip_generic *
  __irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq)
  {
  	struct irq_domain_chip_generic *dgc = d->gc;
  	int idx;
  
  	if (!dgc)
  		return ERR_PTR(-ENODEV);
  	idx = hw_irq / dgc->irqs_per_chip;
  	if (idx >= dgc->num_chips)
  		return ERR_PTR(-EINVAL);
  	return dgc->gc[idx];
  }
088f40b7b   Thomas Gleixner   genirq: Generic c...
336
337
338
339
340
341
342
343
  /**
   * irq_get_domain_generic_chip - Get a pointer to the generic chip of a hw_irq
   * @d:			irq domain pointer
   * @hw_irq:		Hardware interrupt number
   */
  struct irq_chip_generic *
  irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq)
  {
f0c450eaa   Sebastian Frias   genirq/generic_ch...
344
  	struct irq_chip_generic *gc = __irq_get_domain_generic_chip(d, hw_irq);
088f40b7b   Thomas Gleixner   genirq: Generic c...
345

f0c450eaa   Sebastian Frias   genirq/generic_ch...
346
  	return !IS_ERR(gc) ? gc : NULL;
088f40b7b   Thomas Gleixner   genirq: Generic c...
347
348
  }
  EXPORT_SYMBOL_GPL(irq_get_domain_generic_chip);
7d8280624   Thomas Gleixner   genirq: Implement...
349
350
351
352
353
  /*
   * Separate lockdep class for interrupt chip which can nest irq_desc
   * lock.
   */
  static struct lock_class_key irq_nested_lock_class;
ccc414f83   Thomas Gleixner   genirq: Add the g...
354
  /*
088f40b7b   Thomas Gleixner   genirq: Generic c...
355
356
   * irq_map_generic_chip - Map a generic chip for an irq domain
   */
a5152c8a1   Boris BREZILLON   genirq: generic c...
357
358
  int irq_map_generic_chip(struct irq_domain *d, unsigned int virq,
  			 irq_hw_number_t hw_irq)
088f40b7b   Thomas Gleixner   genirq: Generic c...
359
  {
c5863484c   Stefan Agner   genirq: generic c...
360
  	struct irq_data *data = irq_domain_get_irq_data(d, virq);
088f40b7b   Thomas Gleixner   genirq: Generic c...
361
362
363
364
365
366
  	struct irq_domain_chip_generic *dgc = d->gc;
  	struct irq_chip_generic *gc;
  	struct irq_chip_type *ct;
  	struct irq_chip *chip;
  	unsigned long flags;
  	int idx;
f0c450eaa   Sebastian Frias   genirq/generic_ch...
367
368
369
  	gc = __irq_get_domain_generic_chip(d, hw_irq);
  	if (IS_ERR(gc))
  		return PTR_ERR(gc);
088f40b7b   Thomas Gleixner   genirq: Generic c...
370
371
  
  	idx = hw_irq % dgc->irqs_per_chip;
e8bd834f7   Grant Likely   genirq: irqchip: ...
372
373
  	if (test_bit(idx, &gc->unused))
  		return -ENOTSUPP;
088f40b7b   Thomas Gleixner   genirq: Generic c...
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
  	if (test_bit(idx, &gc->installed))
  		return -EBUSY;
  
  	ct = gc->chip_types;
  	chip = &ct->chip;
  
  	/* We only init the cache for the first mapping of a generic chip */
  	if (!gc->installed) {
  		raw_spin_lock_irqsave(&gc->lock, flags);
  		irq_gc_init_mask_cache(gc, dgc->gc_flags);
  		raw_spin_unlock_irqrestore(&gc->lock, flags);
  	}
  
  	/* Mark the interrupt as installed */
  	set_bit(idx, &gc->installed);
  
  	if (dgc->gc_flags & IRQ_GC_INIT_NESTED_LOCK)
  		irq_set_lockdep_class(virq, &irq_nested_lock_class);
  
  	if (chip->irq_calc_mask)
  		chip->irq_calc_mask(data);
  	else
  		data->mask = 1 << idx;
c5863484c   Stefan Agner   genirq: generic c...
397
  	irq_domain_set_info(d, virq, hw_irq, chip, gc, ct->handler, NULL, NULL);
088f40b7b   Thomas Gleixner   genirq: Generic c...
398
399
400
  	irq_modify_status(virq, dgc->irq_flags_to_clear, dgc->irq_flags_to_set);
  	return 0;
  }
ee26c013c   Sebastian Frias   genirq/generic_ch...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  static void irq_unmap_generic_chip(struct irq_domain *d, unsigned int virq)
  {
  	struct irq_data *data = irq_domain_get_irq_data(d, virq);
  	struct irq_domain_chip_generic *dgc = d->gc;
  	unsigned int hw_irq = data->hwirq;
  	struct irq_chip_generic *gc;
  	int irq_idx;
  
  	gc = irq_get_domain_generic_chip(d, hw_irq);
  	if (!gc)
  		return;
  
  	irq_idx = hw_irq % dgc->irqs_per_chip;
  
  	clear_bit(irq_idx, &gc->installed);
  	irq_domain_set_info(d, virq, hw_irq, &no_irq_chip, NULL, NULL, NULL,
  			    NULL);
  
  }
088f40b7b   Thomas Gleixner   genirq: Generic c...
420
421
  struct irq_domain_ops irq_generic_chip_ops = {
  	.map	= irq_map_generic_chip,
ee26c013c   Sebastian Frias   genirq/generic_ch...
422
  	.unmap  = irq_unmap_generic_chip,
088f40b7b   Thomas Gleixner   genirq: Generic c...
423
424
425
426
427
  	.xlate	= irq_domain_xlate_onetwocell,
  };
  EXPORT_SYMBOL_GPL(irq_generic_chip_ops);
  
  /**
7d8280624   Thomas Gleixner   genirq: Implement...
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
   * irq_setup_generic_chip - Setup a range of interrupts with a generic chip
   * @gc:		Generic irq chip holding all data
   * @msk:	Bitmask holding the irqs to initialize relative to gc->irq_base
   * @flags:	Flags for initialization
   * @clr:	IRQ_* bits to clear
   * @set:	IRQ_* bits to set
   *
   * Set up max. 32 interrupts starting from gc->irq_base. Note, this
   * initializes all interrupts to the primary irq_chip_type and its
   * associated handler.
   */
  void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
  			    enum irq_gc_flags flags, unsigned int clr,
  			    unsigned int set)
  {
  	struct irq_chip_type *ct = gc->chip_types;
d0051816e   Thomas Gleixner   genirq: irqchip: ...
444
  	struct irq_chip *chip = &ct->chip;
7d8280624   Thomas Gleixner   genirq: Implement...
445
  	unsigned int i;
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
446
447
448
  	raw_spin_lock(&gc_lock);
  	list_add_tail(&gc->list, &gc_list);
  	raw_spin_unlock(&gc_lock);
3528d82b6   Thomas Gleixner   genirq: Generic c...
449
  	irq_gc_init_mask_cache(gc, flags);
899f0e66f   Gerlando Falauto   genirq: Generic c...
450

7d8280624   Thomas Gleixner   genirq: Implement...
451
  	for (i = gc->irq_base; msk; msk >>= 1, i++) {
1dd75f91a   jhbird.choi@samsung.com   genirq: Fix wrong...
452
  		if (!(msk & 0x01))
7d8280624   Thomas Gleixner   genirq: Implement...
453
454
455
456
  			continue;
  
  		if (flags & IRQ_GC_INIT_NESTED_LOCK)
  			irq_set_lockdep_class(i, &irq_nested_lock_class);
966dc736b   Thomas Gleixner   genirq: Generic c...
457
458
  		if (!(flags & IRQ_GC_NO_MASK)) {
  			struct irq_data *d = irq_get_irq_data(i);
d0051816e   Thomas Gleixner   genirq: irqchip: ...
459
460
461
462
  			if (chip->irq_calc_mask)
  				chip->irq_calc_mask(d);
  			else
  				d->mask = 1 << (i - gc->irq_base);
966dc736b   Thomas Gleixner   genirq: Generic c...
463
  		}
d0051816e   Thomas Gleixner   genirq: irqchip: ...
464
  		irq_set_chip_and_handler(i, chip, ct->handler);
7d8280624   Thomas Gleixner   genirq: Implement...
465
466
467
468
469
  		irq_set_chip_data(i, gc);
  		irq_modify_status(i, clr, set);
  	}
  	gc->irq_cnt = i - gc->irq_base;
  }
825de2e90   Nobuhiro Iwamatsu   irq: Add EXPORT_S...
470
  EXPORT_SYMBOL_GPL(irq_setup_generic_chip);
7d8280624   Thomas Gleixner   genirq: Implement...
471
472
473
474
  
  /**
   * irq_setup_alt_chip - Switch to alternative chip
   * @d:		irq_data for this interrupt
ccc414f83   Thomas Gleixner   genirq: Add the g...
475
   * @type:	Flow type to be initialized
7d8280624   Thomas Gleixner   genirq: Implement...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
   *
   * Only to be called from chip->irq_set_type() callbacks.
   */
  int irq_setup_alt_chip(struct irq_data *d, unsigned int type)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  	struct irq_chip_type *ct = gc->chip_types;
  	unsigned int i;
  
  	for (i = 0; i < gc->num_ct; i++, ct++) {
  		if (ct->type & type) {
  			d->chip = &ct->chip;
  			irq_data_to_desc(d)->handle_irq = ct->handler;
  			return 0;
  		}
  	}
  	return -EINVAL;
  }
825de2e90   Nobuhiro Iwamatsu   irq: Add EXPORT_S...
494
  EXPORT_SYMBOL_GPL(irq_setup_alt_chip);
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
  
  /**
   * irq_remove_generic_chip - Remove a chip
   * @gc:		Generic irq chip holding all data
   * @msk:	Bitmask holding the irqs to initialize relative to gc->irq_base
   * @clr:	IRQ_* bits to clear
   * @set:	IRQ_* bits to set
   *
   * Remove up to 32 interrupts starting from gc->irq_base.
   */
  void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
  			     unsigned int clr, unsigned int set)
  {
  	unsigned int i = gc->irq_base;
  
  	raw_spin_lock(&gc_lock);
  	list_del(&gc->list);
  	raw_spin_unlock(&gc_lock);
  
  	for (; msk; msk >>= 1, i++) {
1dd75f91a   jhbird.choi@samsung.com   genirq: Fix wrong...
515
  		if (!(msk & 0x01))
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
516
517
518
519
520
521
522
523
524
  			continue;
  
  		/* Remove handler first. That will mask the irq line */
  		irq_set_handler(i, NULL);
  		irq_set_chip(i, &no_irq_chip);
  		irq_set_chip_data(i, NULL);
  		irq_modify_status(i, clr, set);
  	}
  }
825de2e90   Nobuhiro Iwamatsu   irq: Add EXPORT_S...
525
  EXPORT_SYMBOL_GPL(irq_remove_generic_chip);
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
526

088f40b7b   Thomas Gleixner   genirq: Generic c...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
  static struct irq_data *irq_gc_get_irq_data(struct irq_chip_generic *gc)
  {
  	unsigned int virq;
  
  	if (!gc->domain)
  		return irq_get_irq_data(gc->irq_base);
  
  	/*
  	 * We don't know which of the irqs has been actually
  	 * installed. Use the first one.
  	 */
  	if (!gc->installed)
  		return NULL;
  
  	virq = irq_find_mapping(gc->domain, gc->irq_base + __ffs(gc->installed));
  	return virq ? irq_get_irq_data(virq) : NULL;
  }
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
544
545
546
547
548
549
550
  #ifdef CONFIG_PM
  static int irq_gc_suspend(void)
  {
  	struct irq_chip_generic *gc;
  
  	list_for_each_entry(gc, &gc_list, list) {
  		struct irq_chip_type *ct = gc->chip_types;
088f40b7b   Thomas Gleixner   genirq: Generic c...
551
552
553
554
555
556
  		if (ct->chip.irq_suspend) {
  			struct irq_data *data = irq_gc_get_irq_data(gc);
  
  			if (data)
  				ct->chip.irq_suspend(data);
  		}
be9b22b6a   Brian Norris   genirq: Add chip_...
557
558
559
  
  		if (gc->suspend)
  			gc->suspend(gc);
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
560
561
562
563
564
565
566
567
568
569
  	}
  	return 0;
  }
  
  static void irq_gc_resume(void)
  {
  	struct irq_chip_generic *gc;
  
  	list_for_each_entry(gc, &gc_list, list) {
  		struct irq_chip_type *ct = gc->chip_types;
be9b22b6a   Brian Norris   genirq: Add chip_...
570
571
  		if (gc->resume)
  			gc->resume(gc);
088f40b7b   Thomas Gleixner   genirq: Generic c...
572
573
574
575
576
577
  		if (ct->chip.irq_resume) {
  			struct irq_data *data = irq_gc_get_irq_data(gc);
  
  			if (data)
  				ct->chip.irq_resume(data);
  		}
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
578
579
580
581
582
583
584
585
586
587
588
589
590
  	}
  }
  #else
  #define irq_gc_suspend NULL
  #define irq_gc_resume NULL
  #endif
  
  static void irq_gc_shutdown(void)
  {
  	struct irq_chip_generic *gc;
  
  	list_for_each_entry(gc, &gc_list, list) {
  		struct irq_chip_type *ct = gc->chip_types;
088f40b7b   Thomas Gleixner   genirq: Generic c...
591
592
593
594
595
596
  		if (ct->chip.irq_pm_shutdown) {
  			struct irq_data *data = irq_gc_get_irq_data(gc);
  
  			if (data)
  				ct->chip.irq_pm_shutdown(data);
  		}
cfefd21e6   Thomas Gleixner   genirq: Add chip ...
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  	}
  }
  
  static struct syscore_ops irq_gc_syscore_ops = {
  	.suspend = irq_gc_suspend,
  	.resume = irq_gc_resume,
  	.shutdown = irq_gc_shutdown,
  };
  
  static int __init irq_gc_init_ops(void)
  {
  	register_syscore_ops(&irq_gc_syscore_ops);
  	return 0;
  }
  device_initcall(irq_gc_init_ops);