13795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner/* 23795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar 33795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner * Copyright (C) 2005-2006, Thomas Gleixner, Russell King 43795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner * 53795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner * This file contains the interrupt descriptor management code 63795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner * 73795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner * Detailed information is available in Documentation/DocBook/genericirq 83795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner * 93795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner */ 103795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#include <linux/irq.h> 113795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#include <linux/slab.h> 12ec53cf23c0ddb0c29950b9a4ac46964c4c6c6c2fPaul Gortmaker#include <linux/export.h> 133795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#include <linux/interrupt.h> 143795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#include <linux/kernel_stat.h> 153795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#include <linux/radix-tree.h> 161f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#include <linux/bitmap.h> 1776ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier#include <linux/irqdomain.h> 183795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 193795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#include "internals.h" 203795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 213795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner/* 223795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner * lockdep: we want to handle all irq_desc locks as a single lock-class: 233795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner */ 2478f90d91f395cd0dc1ef3f21e0c5cd6fd50d202cThomas Gleixnerstatic struct lock_class_key irq_desc_lock_class; 253795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 26fe0514348452f5b0ad7e842b0d71b8322b1297deThomas Gleixner#if defined(CONFIG_SMP) 273795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixnerstatic void __init init_irq_default_affinity(void) 283795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner{ 293795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT); 303795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner cpumask_setall(irq_default_affinity); 313795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner} 323795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#else 333795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixnerstatic void __init init_irq_default_affinity(void) 343795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner{ 353795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner} 363795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#endif 373795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 381f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#ifdef CONFIG_SMP 391f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic int alloc_masks(struct irq_desc *desc, gfp_t gfp, int node) 401f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 411f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner if (!zalloc_cpumask_var_node(&desc->irq_data.affinity, gfp, node)) 421f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return -ENOMEM; 431f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 441f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#ifdef CONFIG_GENERIC_PENDING_IRQ 451f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner if (!zalloc_cpumask_var_node(&desc->pending_mask, gfp, node)) { 461f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner free_cpumask_var(desc->irq_data.affinity); 471f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return -ENOMEM; 481f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner } 491f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#endif 501f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return 0; 511f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 521f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 531f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic void desc_smp_init(struct irq_desc *desc, int node) 541f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 55aa99ec0f3f26bf2bcd0fa5176de93598427f1e5eThomas Gleixner desc->irq_data.node = node; 561f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner cpumask_copy(desc->irq_data.affinity, irq_default_affinity); 57b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixner#ifdef CONFIG_GENERIC_PENDING_IRQ 58b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixner cpumask_clear(desc->pending_mask); 59b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixner#endif 60b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixner} 61b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixner 62b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixnerstatic inline int desc_node(struct irq_desc *desc) 63b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixner{ 64b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixner return desc->irq_data.node; 651f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 661f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 671f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#else 681f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic inline int 691f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixneralloc_masks(struct irq_desc *desc, gfp_t gfp, int node) { return 0; } 701f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic inline void desc_smp_init(struct irq_desc *desc, int node) { } 71b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixnerstatic inline int desc_node(struct irq_desc *desc) { return 0; } 721f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#endif 731f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 74b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewiorstatic void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node, 75b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior struct module *owner) 761f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 776c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet int cpu; 786c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet 791f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc->irq_data.irq = irq; 801f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc->irq_data.chip = &no_irq_chip; 811f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc->irq_data.chip_data = NULL; 821f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc->irq_data.handler_data = NULL; 831f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc->irq_data.msi_desc = NULL; 84f9e4989eb8183a1f33581fa1b99274287b0639d2Thomas Gleixner irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS); 85801a0e9ae36e9b487092e31699d28c0b9a21ad52Thomas Gleixner irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED); 861f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc->handle_irq = handle_bad_irq; 871f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc->depth = 1; 88b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixner desc->irq_count = 0; 89b7b29338dc7111ed8bd4d6555d84afae13ebe752Thomas Gleixner desc->irqs_unhandled = 0; 901f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc->name = NULL; 91b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior desc->owner = owner; 926c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet for_each_possible_cpu(cpu) 936c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet *per_cpu_ptr(desc->kstat_irqs, cpu) = 0; 941f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc_smp_init(desc, node); 951f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 961f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 973795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixnerint nr_irqs = NR_IRQS; 983795de236d67a05994a1a12759db9d4dd9ffc42cThomas GleixnerEXPORT_SYMBOL_GPL(nr_irqs); 993795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 100a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixnerstatic DEFINE_MUTEX(sparse_irq_lock); 101c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixnerstatic DECLARE_BITMAP(allocated_irqs, IRQ_BITMAP_BITS); 1021f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1033795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#ifdef CONFIG_SPARSE_IRQ 1043795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 105baa0d233afe765daa6dc01ff233aea8c5944f534Thomas Gleixnerstatic RADIX_TREE(irq_desc_tree, GFP_KERNEL); 1063795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 1071f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic void irq_insert_desc(unsigned int irq, struct irq_desc *desc) 1083795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner{ 1093795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner radix_tree_insert(&irq_desc_tree, irq, desc); 1103795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner} 1113795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 1123795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixnerstruct irq_desc *irq_to_desc(unsigned int irq) 1133795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner{ 1143795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner return radix_tree_lookup(&irq_desc_tree, irq); 1153795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner} 1163911ff30f5d1175e2e67e73244405e3492b35c79Jiri KosinaEXPORT_SYMBOL(irq_to_desc); 1173795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 1181f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic void delete_irq_desc(unsigned int irq) 1191f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 1201f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner radix_tree_delete(&irq_desc_tree, irq); 1211f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 1221f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1231f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#ifdef CONFIG_SMP 1241f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic void free_masks(struct irq_desc *desc) 1251f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 1261f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#ifdef CONFIG_GENERIC_PENDING_IRQ 1271f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner free_cpumask_var(desc->pending_mask); 1281f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#endif 129c0a19ebc018222ffd1dd93af5b53d9efd779c19bThomas Gleixner free_cpumask_var(desc->irq_data.affinity); 1301f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 1311f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#else 1321f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic inline void free_masks(struct irq_desc *desc) { } 1331f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner#endif 1341f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 135b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewiorstatic struct irq_desc *alloc_desc(int irq, int node, struct module *owner) 1361f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 1371f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner struct irq_desc *desc; 138baa0d233afe765daa6dc01ff233aea8c5944f534Thomas Gleixner gfp_t gfp = GFP_KERNEL; 1391f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1401f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner desc = kzalloc_node(sizeof(*desc), gfp, node); 1411f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner if (!desc) 1421f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return NULL; 1431f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner /* allocate based on nr_cpu_ids */ 1446c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet desc->kstat_irqs = alloc_percpu(unsigned int); 1451f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner if (!desc->kstat_irqs) 1461f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner goto err_desc; 1471f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1481f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner if (alloc_masks(desc, gfp, node)) 1491f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner goto err_kstat; 1501f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1511f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner raw_spin_lock_init(&desc->lock); 1521f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner lockdep_set_class(&desc->lock, &irq_desc_lock_class); 1531f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 154b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior desc_set_defaults(irq, desc, node, owner); 1551f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1561f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return desc; 1571f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1581f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnererr_kstat: 1596c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet free_percpu(desc->kstat_irqs); 1601f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnererr_desc: 1611f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner kfree(desc); 1621f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return NULL; 1631f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 1641f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1651f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic void free_desc(unsigned int irq) 1661f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 1671f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner struct irq_desc *desc = irq_to_desc(irq); 1681f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 16913bfe99e09123ef5edb6acb81ba337d2db600b53Thomas Gleixner unregister_irq_proc(irq, desc); 17013bfe99e09123ef5edb6acb81ba337d2db600b53Thomas Gleixner 171a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_lock(&sparse_irq_lock); 1721f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner delete_irq_desc(irq); 173a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_unlock(&sparse_irq_lock); 1741f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1751f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner free_masks(desc); 1766c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet free_percpu(desc->kstat_irqs); 1771f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner kfree(desc); 1781f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 1791f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 180b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewiorstatic int alloc_descs(unsigned int start, unsigned int cnt, int node, 181b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior struct module *owner) 1821f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 1831f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner struct irq_desc *desc; 1841f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner int i; 1851f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1861f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner for (i = 0; i < cnt; i++) { 187b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior desc = alloc_desc(start + i, node, owner); 1881f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner if (!desc) 1891f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner goto err; 190a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_lock(&sparse_irq_lock); 1911f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner irq_insert_desc(start + i, desc); 192a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_unlock(&sparse_irq_lock); 1931f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner } 1941f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return start; 1951f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 1961f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnererr: 1971f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner for (i--; i >= 0; i--) 1981f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner free_desc(start + i); 1991f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 200a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_lock(&sparse_irq_lock); 2011f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner bitmap_clear(allocated_irqs, start, cnt); 202a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_unlock(&sparse_irq_lock); 2031f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return -ENOMEM; 2041f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 2051f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 206ed4dea6e0e33a3e58d8b77b775a8f0e433e7a005Yinghai Lustatic int irq_expand_nr_irqs(unsigned int nr) 207e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner{ 208ed4dea6e0e33a3e58d8b77b775a8f0e433e7a005Yinghai Lu if (nr > IRQ_BITMAP_BITS) 209e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner return -ENOMEM; 210ed4dea6e0e33a3e58d8b77b775a8f0e433e7a005Yinghai Lu nr_irqs = nr; 211e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner return 0; 212e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner} 213e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner 2143795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixnerint __init early_irq_init(void) 2153795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner{ 216b683de2b3cb17bb10fa6fd4af614dc75b5749fe0Thomas Gleixner int i, initcnt, node = first_online_node; 2173795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner struct irq_desc *desc; 2183795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2193795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner init_irq_default_affinity(); 2203795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 221b683de2b3cb17bb10fa6fd4af614dc75b5749fe0Thomas Gleixner /* Let arch update nr_irqs and return the nr of preallocated irqs */ 222b683de2b3cb17bb10fa6fd4af614dc75b5749fe0Thomas Gleixner initcnt = arch_probe_nr_irqs(); 223b683de2b3cb17bb10fa6fd4af614dc75b5749fe0Thomas Gleixner printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d %d\n", NR_IRQS, nr_irqs, initcnt); 2243795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 225c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixner if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS)) 226c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixner nr_irqs = IRQ_BITMAP_BITS; 227c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixner 228c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixner if (WARN_ON(initcnt > IRQ_BITMAP_BITS)) 229c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixner initcnt = IRQ_BITMAP_BITS; 230c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixner 231c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixner if (initcnt > nr_irqs) 232c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixner nr_irqs = initcnt; 233c1ee6264280e740a9d3ff3feef38642cf0a57013Thomas Gleixner 234b683de2b3cb17bb10fa6fd4af614dc75b5749fe0Thomas Gleixner for (i = 0; i < initcnt; i++) { 235b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior desc = alloc_desc(i, node, NULL); 236aa99ec0f3f26bf2bcd0fa5176de93598427f1e5eThomas Gleixner set_bit(i, allocated_irqs); 237aa99ec0f3f26bf2bcd0fa5176de93598427f1e5eThomas Gleixner irq_insert_desc(i, desc); 2383795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner } 2393795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner return arch_early_irq_init(); 2403795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner} 2413795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2423795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#else /* !CONFIG_SPARSE_IRQ */ 2433795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2443795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixnerstruct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { 2453795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner [0 ... NR_IRQS-1] = { 2463795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner .handle_irq = handle_bad_irq, 2473795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner .depth = 1, 2483795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock), 2493795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner } 2503795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner}; 2513795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2523795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixnerint __init early_irq_init(void) 2533795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner{ 254aa99ec0f3f26bf2bcd0fa5176de93598427f1e5eThomas Gleixner int count, i, node = first_online_node; 2553795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner struct irq_desc *desc; 2563795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2573795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner init_irq_default_affinity(); 2583795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2593795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS); 2603795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2613795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner desc = irq_desc; 2623795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner count = ARRAY_SIZE(irq_desc); 2633795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2643795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner for (i = 0; i < count; i++) { 2656c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet desc[i].kstat_irqs = alloc_percpu(unsigned int); 266e7fbad300a7a6432238f086e3c9a61538a905858Linus Walleij alloc_masks(&desc[i], GFP_KERNEL, node); 267e7fbad300a7a6432238f086e3c9a61538a905858Linus Walleij raw_spin_lock_init(&desc[i].lock); 268154cd387cdf0e5566ce523cbddf92dd2a062dfd6Thomas Gleixner lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); 269b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior desc_set_defaults(i, &desc[i], node, NULL); 2703795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner } 2713795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner return arch_early_irq_init(); 2723795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner} 2733795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2743795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixnerstruct irq_desc *irq_to_desc(unsigned int irq) 2753795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner{ 2763795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner return (irq < NR_IRQS) ? irq_desc + irq : NULL; 2773795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner} 2782c45aada341121438affc4cb8d5b4cfaa2813d3dPaul GortmakerEXPORT_SYMBOL(irq_to_desc); 2793795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 2801f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerstatic void free_desc(unsigned int irq) 2811f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 282d8179bc0db8d0c9654d5de43de2874bf6d0a58faThomas Gleixner struct irq_desc *desc = irq_to_desc(irq); 283d8179bc0db8d0c9654d5de43de2874bf6d0a58faThomas Gleixner unsigned long flags; 284d8179bc0db8d0c9654d5de43de2874bf6d0a58faThomas Gleixner 285d8179bc0db8d0c9654d5de43de2874bf6d0a58faThomas Gleixner raw_spin_lock_irqsave(&desc->lock, flags); 286d8179bc0db8d0c9654d5de43de2874bf6d0a58faThomas Gleixner desc_set_defaults(irq, desc, desc_node(desc), NULL); 287d8179bc0db8d0c9654d5de43de2874bf6d0a58faThomas Gleixner raw_spin_unlock_irqrestore(&desc->lock, flags); 2881f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 2891f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 290b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewiorstatic inline int alloc_descs(unsigned int start, unsigned int cnt, int node, 291b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior struct module *owner) 2921f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 293b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior u32 i; 294b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior 295b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior for (i = 0; i < cnt; i++) { 296b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior struct irq_desc *desc = irq_to_desc(start + i); 297b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior 298b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior desc->owner = owner; 299b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior } 3001f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return start; 3011f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 302e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner 303ed4dea6e0e33a3e58d8b77b775a8f0e433e7a005Yinghai Lustatic int irq_expand_nr_irqs(unsigned int nr) 304e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner{ 305e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner return -ENOMEM; 306e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner} 307e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner 308f63b6a05f2b11537612266a8b27a61f412344a1dThomas Gleixnervoid irq_mark_irq(unsigned int irq) 309f63b6a05f2b11537612266a8b27a61f412344a1dThomas Gleixner{ 310f63b6a05f2b11537612266a8b27a61f412344a1dThomas Gleixner mutex_lock(&sparse_irq_lock); 311f63b6a05f2b11537612266a8b27a61f412344a1dThomas Gleixner bitmap_set(allocated_irqs, irq, 1); 312f63b6a05f2b11537612266a8b27a61f412344a1dThomas Gleixner mutex_unlock(&sparse_irq_lock); 313f63b6a05f2b11537612266a8b27a61f412344a1dThomas Gleixner} 314f63b6a05f2b11537612266a8b27a61f412344a1dThomas Gleixner 315c940e01c94e73a2a5318f1b82038e0746aaec753Thomas Gleixner#ifdef CONFIG_GENERIC_IRQ_LEGACY 316c940e01c94e73a2a5318f1b82038e0746aaec753Thomas Gleixnervoid irq_init_desc(unsigned int irq) 317c940e01c94e73a2a5318f1b82038e0746aaec753Thomas Gleixner{ 318d8179bc0db8d0c9654d5de43de2874bf6d0a58faThomas Gleixner free_desc(irq); 319c940e01c94e73a2a5318f1b82038e0746aaec753Thomas Gleixner} 320c940e01c94e73a2a5318f1b82038e0746aaec753Thomas Gleixner#endif 321c940e01c94e73a2a5318f1b82038e0746aaec753Thomas Gleixner 3223795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner#endif /* !CONFIG_SPARSE_IRQ */ 3233795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner 324fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner/** 325fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner * generic_handle_irq - Invoke the handler for a particular irq 326fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner * @irq: The irq number to handle 327fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner * 328fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner */ 329fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixnerint generic_handle_irq(unsigned int irq) 330fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner{ 331fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner struct irq_desc *desc = irq_to_desc(irq); 332fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner 333fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner if (!desc) 334fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner return -EINVAL; 335fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner generic_handle_irq_desc(irq, desc); 336fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner return 0; 337fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner} 338edf76f8307c350bcb81f0c760118a991b3e62956Jonathan CameronEXPORT_SYMBOL_GPL(generic_handle_irq); 339fe12bc2c996d3e492b2920e32ac79f7bbae3e15dThomas Gleixner 34076ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier#ifdef CONFIG_HANDLE_DOMAIN_IRQ 34176ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier/** 34276ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier * __handle_domain_irq - Invoke the handler for a HW irq belonging to a domain 34376ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier * @domain: The domain where to perform the lookup 34476ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier * @hwirq: The HW irq number to convert to a logical one 34576ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier * @lookup: Whether to perform the domain lookup or not 34676ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier * @regs: Register file coming from the low-level handling code 34776ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier * 34876ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier * Returns: 0 on success, or -EINVAL if conversion has failed 34976ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier */ 35076ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngierint __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, 35176ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier bool lookup, struct pt_regs *regs) 35276ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier{ 35376ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier struct pt_regs *old_regs = set_irq_regs(regs); 35476ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier unsigned int irq = hwirq; 35576ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier int ret = 0; 35676ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier 35776ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier irq_enter(); 35876ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier 35976ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier#ifdef CONFIG_IRQ_DOMAIN 36076ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier if (lookup) 36176ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier irq = irq_find_mapping(domain, hwirq); 36276ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier#endif 36376ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier 36476ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier /* 36576ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier * Some hardware gives randomly wrong interrupts. Rather 36676ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier * than crashing, do something sensible. 36776ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier */ 36876ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier if (unlikely(!irq || irq >= nr_irqs)) { 36976ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier ack_bad_irq(irq); 37076ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier ret = -EINVAL; 37176ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier } else { 37276ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier generic_handle_irq(irq); 37376ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier } 37476ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier 37576ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier irq_exit(); 37676ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier set_irq_regs(old_regs); 37776ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier return ret; 37876ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier} 37976ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier#endif 38076ba59f8366f2d9282cb5bda9de75b4b68cbe55fMarc Zyngier 3811f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner/* Dynamic interrupt handling */ 3821f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 3831f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner/** 3841f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * irq_free_descs - free irq descriptors 3851f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * @from: Start of descriptor range 3861f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * @cnt: Number of consecutive irqs to free 3871f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner */ 3881f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnervoid irq_free_descs(unsigned int from, unsigned int cnt) 3891f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 3901f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner int i; 3911f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 3921f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner if (from >= nr_irqs || (from + cnt) > nr_irqs) 3931f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return; 3941f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 3951f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner for (i = 0; i < cnt; i++) 3961f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner free_desc(from + i); 3971f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 398a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_lock(&sparse_irq_lock); 3991f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner bitmap_clear(allocated_irqs, from, cnt); 400a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_unlock(&sparse_irq_lock); 4011f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 402edf76f8307c350bcb81f0c760118a991b3e62956Jonathan CameronEXPORT_SYMBOL_GPL(irq_free_descs); 4031f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 4041f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner/** 4051f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * irq_alloc_descs - allocate and initialize a range of irq descriptors 4061f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * @irq: Allocate for specific irq number if irq >= 0 4071f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * @from: Start the search from this irq number 4081f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * @cnt: Number of consecutive irqs to allocate. 4091f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * @node: Preferred node on which the irq descriptor should be allocated 410d522a0d17963e9c2e556db2cbd60c96d40505b6cRandy Dunlap * @owner: Owning module (can be NULL) 4111f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * 4121f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner * Returns the first irq number or error code 4131f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner */ 4141f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnerint __ref 415b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, 416b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior struct module *owner) 4171f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner{ 4181f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner int start, ret; 4191f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 4201f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner if (!cnt) 4211f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return -EINVAL; 4221f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 423c5182b8867e189e14a8df5dbfcba1c73f286e061Mark Brown if (irq >= 0) { 424c5182b8867e189e14a8df5dbfcba1c73f286e061Mark Brown if (from > irq) 425c5182b8867e189e14a8df5dbfcba1c73f286e061Mark Brown return -EINVAL; 426c5182b8867e189e14a8df5dbfcba1c73f286e061Mark Brown from = irq; 42762a08ae2a5763aabeee98264605236b001503e0cThomas Gleixner } else { 42862a08ae2a5763aabeee98264605236b001503e0cThomas Gleixner /* 42962a08ae2a5763aabeee98264605236b001503e0cThomas Gleixner * For interrupts which are freely allocated the 43062a08ae2a5763aabeee98264605236b001503e0cThomas Gleixner * architecture can force a lower bound to the @from 43162a08ae2a5763aabeee98264605236b001503e0cThomas Gleixner * argument. x86 uses this to exclude the GSI space. 43262a08ae2a5763aabeee98264605236b001503e0cThomas Gleixner */ 43362a08ae2a5763aabeee98264605236b001503e0cThomas Gleixner from = arch_dynirq_lower_bound(from); 434c5182b8867e189e14a8df5dbfcba1c73f286e061Mark Brown } 435c5182b8867e189e14a8df5dbfcba1c73f286e061Mark Brown 436a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_lock(&sparse_irq_lock); 4371f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 438ed4dea6e0e33a3e58d8b77b775a8f0e433e7a005Yinghai Lu start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS, 439ed4dea6e0e33a3e58d8b77b775a8f0e433e7a005Yinghai Lu from, cnt, 0); 4401f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner ret = -EEXIST; 4411f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner if (irq >=0 && start != irq) 4421f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner goto err; 4431f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 444ed4dea6e0e33a3e58d8b77b775a8f0e433e7a005Yinghai Lu if (start + cnt > nr_irqs) { 445ed4dea6e0e33a3e58d8b77b775a8f0e433e7a005Yinghai Lu ret = irq_expand_nr_irqs(start + cnt); 446e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner if (ret) 447e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner goto err; 448e7bcecb7b1d29b9ad5af939149a945658620ca8fThomas Gleixner } 4491f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 4501f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner bitmap_set(allocated_irqs, start, cnt); 451a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_unlock(&sparse_irq_lock); 452b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej Siewior return alloc_descs(start, cnt, node, owner); 4531f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 4541f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixnererr: 455a05a900a51c7622ebd8ddb41f14f8bf9db599d8dThomas Gleixner mutex_unlock(&sparse_irq_lock); 4561f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner return ret; 4571f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner} 458b6873807a7143b7d6d8b06809295e559d07d7debSebastian Andrzej SiewiorEXPORT_SYMBOL_GPL(__irq_alloc_descs); 4591f5a5b87f78fade3ae48dfd55e8765d1d622ea4eThomas Gleixner 4607b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner#ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ 4617b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner/** 4627b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner * irq_alloc_hwirqs - Allocate an irq descriptor and initialize the hardware 4637b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner * @cnt: number of interrupts to allocate 4647b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner * @node: node on which to allocate 4657b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner * 4667b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner * Returns an interrupt number > 0 or 0, if the allocation fails. 4677b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner */ 4687b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixnerunsigned int irq_alloc_hwirqs(int cnt, int node) 4697b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner{ 4707b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL); 4717b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner 4727b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner if (irq < 0) 4737b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner return 0; 4747b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner 4757b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner for (i = irq; cnt > 0; i++, cnt--) { 4767b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner if (arch_setup_hwirq(i, node)) 4777b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner goto err; 4787b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner irq_clear_status_flags(i, _IRQ_NOREQUEST); 4797b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner } 4807b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner return irq; 4817b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner 4827b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixnererr: 4837b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner for (i--; i >= irq; i--) { 4847b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); 4857b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner arch_teardown_hwirq(i); 4867b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner } 4877b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner irq_free_descs(irq, cnt); 4887b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner return 0; 4897b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner} 4907b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas GleixnerEXPORT_SYMBOL_GPL(irq_alloc_hwirqs); 4917b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner 4927b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner/** 4937b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner * irq_free_hwirqs - Free irq descriptor and cleanup the hardware 4947b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner * @from: Free from irq number 4957b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner * @cnt: number of interrupts to free 4967b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner * 4977b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner */ 4987b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixnervoid irq_free_hwirqs(unsigned int from, int cnt) 4997b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner{ 5008844aad89ed61545b4db6a3467e1b21ca1c49460Keith Busch int i, j; 5017b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner 5028844aad89ed61545b4db6a3467e1b21ca1c49460Keith Busch for (i = from, j = cnt; j > 0; i++, j--) { 5037b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); 5047b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner arch_teardown_hwirq(i); 5057b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner } 5067b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner irq_free_descs(from, cnt); 5077b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner} 5087b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas GleixnerEXPORT_SYMBOL_GPL(irq_free_hwirqs); 5097b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner#endif 5107b6ef1262549f6afc5c881aaef80beb8fd15f908Thomas Gleixner 511a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner/** 512a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner * irq_get_next_irq - get next allocated irq number 513a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner * @offset: where to start the search 514a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner * 515a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner * Returns next irq number after offset or nr_irqs if none is found. 516a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner */ 517a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixnerunsigned int irq_get_next_irq(unsigned int offset) 518a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner{ 519a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner return find_next_bit(allocated_irqs, nr_irqs, offset); 520a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner} 521a98d24b71b6e229965f18dc00d28dc71cb8fe324Thomas Gleixner 522d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixnerstruct irq_desc * 52331d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus, 52431d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier unsigned int check) 525d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner{ 526d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner struct irq_desc *desc = irq_to_desc(irq); 527d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner 528d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner if (desc) { 52931d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier if (check & _IRQ_DESC_CHECK) { 53031d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier if ((check & _IRQ_DESC_PERCPU) && 53131d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier !irq_settings_is_per_cpu_devid(desc)) 53231d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier return NULL; 53331d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier 53431d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier if (!(check & _IRQ_DESC_PERCPU) && 53531d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier irq_settings_is_per_cpu_devid(desc)) 53631d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier return NULL; 53731d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier } 53831d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier 539d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner if (bus) 540d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner chip_bus_lock(desc); 541d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner raw_spin_lock_irqsave(&desc->lock, *flags); 542d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner } 543d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner return desc; 544d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner} 545d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner 546d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixnervoid __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus) 547d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner{ 548d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner raw_spin_unlock_irqrestore(&desc->lock, flags); 549d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner if (bus) 550d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner chip_bus_sync_unlock(desc); 551d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner} 552d5eb4ad2dfb2dfae43fd51bc8630b4fc3ef00e92Thomas Gleixner 55331d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngierint irq_set_percpu_devid(unsigned int irq) 55431d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier{ 55531d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier struct irq_desc *desc = irq_to_desc(irq); 55631d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier 55731d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier if (!desc) 55831d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier return -EINVAL; 55931d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier 56031d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier if (desc->percpu_enabled) 56131d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier return -EINVAL; 56231d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier 56331d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier desc->percpu_enabled = kzalloc(sizeof(*desc->percpu_enabled), GFP_KERNEL); 56431d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier 56531d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier if (!desc->percpu_enabled) 56631d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier return -ENOMEM; 56731d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier 56831d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier irq_set_percpu_devid_flags(irq); 56931d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier return 0; 57031d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier} 57131d9d9b6d83030f748d013e61502fa5477e2ac0eMarc Zyngier 572792d0018a5fe31ef8ef9d07a7a02081d4abdf6b7Thomas Gleixnervoid kstat_incr_irq_this_cpu(unsigned int irq) 573792d0018a5fe31ef8ef9d07a7a02081d4abdf6b7Thomas Gleixner{ 574792d0018a5fe31ef8ef9d07a7a02081d4abdf6b7Thomas Gleixner kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); 575792d0018a5fe31ef8ef9d07a7a02081d4abdf6b7Thomas Gleixner} 576792d0018a5fe31ef8ef9d07a7a02081d4abdf6b7Thomas Gleixner 5773795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixnerunsigned int kstat_irqs_cpu(unsigned int irq, int cpu) 5783795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner{ 5793795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner struct irq_desc *desc = irq_to_desc(irq); 5806c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet 5816c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet return desc && desc->kstat_irqs ? 5826c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; 5833795de236d67a05994a1a12759db9d4dd9ffc42cThomas Gleixner} 584478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki 585478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyukiunsigned int kstat_irqs(unsigned int irq) 586478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki{ 587478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki struct irq_desc *desc = irq_to_desc(irq); 588478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki int cpu; 589478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki int sum = 0; 590478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki 5916c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet if (!desc || !desc->kstat_irqs) 592478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki return 0; 593478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) 5946c9ae009b298753a3baf71298d676a68b5a10c8fEric Dumazet sum += *per_cpu_ptr(desc->kstat_irqs, cpu); 595478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki return sum; 596478735e38887077ac77a9756121b6ce0cb956e2fKAMEZAWA Hiroyuki} 597