aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/generic-chip.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/irq/generic-chip.c')
-rw-r--r--kernel/irq/generic-chip.c187
1 files changed, 181 insertions, 6 deletions
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index 3deb3333d53e..8743d62fded7 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -7,6 +7,7 @@
7#include <linux/irq.h> 7#include <linux/irq.h>
8#include <linux/slab.h> 8#include <linux/slab.h>
9#include <linux/export.h> 9#include <linux/export.h>
10#include <linux/irqdomain.h>
10#include <linux/interrupt.h> 11#include <linux/interrupt.h>
11#include <linux/kernel_stat.h> 12#include <linux/kernel_stat.h>
12#include <linux/syscore_ops.h> 13#include <linux/syscore_ops.h>
@@ -244,6 +245,90 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags)
244 } 245 }
245} 246}
246 247
248/**
249 * irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain
250 * @d: irq domain for which to allocate chips
251 * @irqs_per_chip: Number of interrupts each chip handles
252 * @num_ct: Number of irq_chip_type instances associated with this
253 * @name: Name of the irq chip
254 * @handler: Default flow handler associated with these chips
255 * @clr: IRQ_* bits to clear in the mapping function
256 * @set: IRQ_* bits to set in the mapping function
257 */
258int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
259 int num_ct, const char *name,
260 irq_flow_handler_t handler,
261 unsigned int clr, unsigned int set,
262 enum irq_gc_flags gcflags)
263{
264 struct irq_domain_chip_generic *dgc;
265 struct irq_chip_generic *gc;
266 int numchips, sz, i;
267 unsigned long flags;
268 void *tmp;
269
270 if (d->gc)
271 return -EBUSY;
272
273 if (d->revmap_type != IRQ_DOMAIN_MAP_LINEAR)
274 return -EINVAL;
275
276 numchips = d->revmap_data.linear.size / irqs_per_chip;
277 if (!numchips)
278 return -EINVAL;
279
280 /* Allocate a pointer, generic chip and chiptypes for each chip */
281 sz = sizeof(*dgc) + numchips * sizeof(gc);
282 sz += numchips * (sizeof(*gc) + num_ct * sizeof(struct irq_chip_type));
283
284 tmp = dgc = kzalloc(sz, GFP_KERNEL);
285 if (!dgc)
286 return -ENOMEM;
287 dgc->irqs_per_chip = irqs_per_chip;
288 dgc->num_chips = numchips;
289 dgc->irq_flags_to_set = set;
290 dgc->irq_flags_to_clear = clr;
291 dgc->gc_flags = gcflags;
292 d->gc = dgc;
293
294 /* Calc pointer to the first generic chip */
295 tmp += sizeof(*dgc) + numchips * sizeof(gc);
296 for (i = 0; i < numchips; i++) {
297 /* Store the pointer to the generic chip */
298 dgc->gc[i] = gc = tmp;
299 irq_init_generic_chip(gc, name, num_ct, i * irqs_per_chip,
300 NULL, handler);
301 gc->domain = d;
302 raw_spin_lock_irqsave(&gc_lock, flags);
303 list_add_tail(&gc->list, &gc_list);
304 raw_spin_unlock_irqrestore(&gc_lock, flags);
305 /* Calc pointer to the next generic chip */
306 tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type);
307 }
308 return 0;
309}
310EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips);
311
312/**
313 * irq_get_domain_generic_chip - Get a pointer to the generic chip of a hw_irq
314 * @d: irq domain pointer
315 * @hw_irq: Hardware interrupt number
316 */
317struct irq_chip_generic *
318irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq)
319{
320 struct irq_domain_chip_generic *dgc = d->gc;
321 int idx;
322
323 if (!dgc)
324 return NULL;
325 idx = hw_irq / dgc->irqs_per_chip;
326 if (idx >= dgc->num_chips)
327 return NULL;
328 return dgc->gc[idx];
329}
330EXPORT_SYMBOL_GPL(irq_get_domain_generic_chip);
331
247/* 332/*
248 * Separate lockdep class for interrupt chip which can nest irq_desc 333 * Separate lockdep class for interrupt chip which can nest irq_desc
249 * lock. 334 * lock.
@@ -251,6 +336,66 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags)
251static struct lock_class_key irq_nested_lock_class; 336static struct lock_class_key irq_nested_lock_class;
252 337
253/** 338/**
339 * irq_map_generic_chip - Map a generic chip for an irq domain
340 */
341static int irq_map_generic_chip(struct irq_domain *d, unsigned int virq,
342 irq_hw_number_t hw_irq)
343{
344 struct irq_data *data = irq_get_irq_data(virq);
345 struct irq_domain_chip_generic *dgc = d->gc;
346 struct irq_chip_generic *gc;
347 struct irq_chip_type *ct;
348 struct irq_chip *chip;
349 unsigned long flags;
350 int idx;
351
352 if (!d->gc)
353 return -ENODEV;
354
355 idx = hw_irq / dgc->irqs_per_chip;
356 if (idx >= dgc->num_chips)
357 return -EINVAL;
358 gc = dgc->gc[idx];
359
360 idx = hw_irq % dgc->irqs_per_chip;
361
362 if (test_bit(idx, &gc->installed))
363 return -EBUSY;
364
365 ct = gc->chip_types;
366 chip = &ct->chip;
367
368 /* We only init the cache for the first mapping of a generic chip */
369 if (!gc->installed) {
370 raw_spin_lock_irqsave(&gc->lock, flags);
371 irq_gc_init_mask_cache(gc, dgc->gc_flags);
372 raw_spin_unlock_irqrestore(&gc->lock, flags);
373 }
374
375 /* Mark the interrupt as installed */
376 set_bit(idx, &gc->installed);
377
378 if (dgc->gc_flags & IRQ_GC_INIT_NESTED_LOCK)
379 irq_set_lockdep_class(virq, &irq_nested_lock_class);
380
381 if (chip->irq_calc_mask)
382 chip->irq_calc_mask(data);
383 else
384 data->mask = 1 << idx;
385
386 irq_set_chip_and_handler(virq, chip, ct->handler);
387 irq_set_chip_data(virq, gc);
388 irq_modify_status(virq, dgc->irq_flags_to_clear, dgc->irq_flags_to_set);
389 return 0;
390}
391
392struct irq_domain_ops irq_generic_chip_ops = {
393 .map = irq_map_generic_chip,
394 .xlate = irq_domain_xlate_onetwocell,
395};
396EXPORT_SYMBOL_GPL(irq_generic_chip_ops);
397
398/**
254 * irq_setup_generic_chip - Setup a range of interrupts with a generic chip 399 * irq_setup_generic_chip - Setup a range of interrupts with a generic chip
255 * @gc: Generic irq chip holding all data 400 * @gc: Generic irq chip holding all data
256 * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base 401 * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base
@@ -354,6 +499,24 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
354} 499}
355EXPORT_SYMBOL_GPL(irq_remove_generic_chip); 500EXPORT_SYMBOL_GPL(irq_remove_generic_chip);
356 501
502static struct irq_data *irq_gc_get_irq_data(struct irq_chip_generic *gc)
503{
504 unsigned int virq;
505
506 if (!gc->domain)
507 return irq_get_irq_data(gc->irq_base);
508
509 /*
510 * We don't know which of the irqs has been actually
511 * installed. Use the first one.
512 */
513 if (!gc->installed)
514 return NULL;
515
516 virq = irq_find_mapping(gc->domain, gc->irq_base + __ffs(gc->installed));
517 return virq ? irq_get_irq_data(virq) : NULL;
518}
519
357#ifdef CONFIG_PM 520#ifdef CONFIG_PM
358static int irq_gc_suspend(void) 521static int irq_gc_suspend(void)
359{ 522{
@@ -362,8 +525,12 @@ static int irq_gc_suspend(void)
362 list_for_each_entry(gc, &gc_list, list) { 525 list_for_each_entry(gc, &gc_list, list) {
363 struct irq_chip_type *ct = gc->chip_types; 526 struct irq_chip_type *ct = gc->chip_types;
364 527
365 if (ct->chip.irq_suspend) 528 if (ct->chip.irq_suspend) {
366 ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base)); 529 struct irq_data *data = irq_gc_get_irq_data(gc);
530
531 if (data)
532 ct->chip.irq_suspend(data);
533 }
367 } 534 }
368 return 0; 535 return 0;
369} 536}
@@ -375,8 +542,12 @@ static void irq_gc_resume(void)
375 list_for_each_entry(gc, &gc_list, list) { 542 list_for_each_entry(gc, &gc_list, list) {
376 struct irq_chip_type *ct = gc->chip_types; 543 struct irq_chip_type *ct = gc->chip_types;
377 544
378 if (ct->chip.irq_resume) 545 if (ct->chip.irq_resume) {
379 ct->chip.irq_resume(irq_get_irq_data(gc->irq_base)); 546 struct irq_data *data = irq_gc_get_irq_data(gc);
547
548 if (data)
549 ct->chip.irq_resume(data);
550 }
380 } 551 }
381} 552}
382#else 553#else
@@ -391,8 +562,12 @@ static void irq_gc_shutdown(void)
391 list_for_each_entry(gc, &gc_list, list) { 562 list_for_each_entry(gc, &gc_list, list) {
392 struct irq_chip_type *ct = gc->chip_types; 563 struct irq_chip_type *ct = gc->chip_types;
393 564
394 if (ct->chip.irq_pm_shutdown) 565 if (ct->chip.irq_pm_shutdown) {
395 ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base)); 566 struct irq_data *data = irq_gc_get_irq_data(gc);
567
568 if (data)
569 ct->chip.irq_pm_shutdown(data);
570 }
396 } 571 }
397} 572}
398 573