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