1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * This file contains the /proc/irq/ handling code.
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds #include <linux/irq.h>
95a0e3ad6STejun Heo #include <linux/gfp.h>
101da177e4SLinus Torvalds #include <linux/proc_fs.h>
11f18e439dSAlexey Dobriyan #include <linux/seq_file.h>
121da177e4SLinus Torvalds #include <linux/interrupt.h>
13c78b9b65SThomas Gleixner #include <linux/kernel_stat.h>
1495c2b175SBen Hutchings #include <linux/mutex.h>
151da177e4SLinus Torvalds
1697a41e26SAdrian Bunk #include "internals.h"
1797a41e26SAdrian Bunk
18c291ee62SThomas Gleixner /*
19c291ee62SThomas Gleixner * Access rules:
20c291ee62SThomas Gleixner *
21c291ee62SThomas Gleixner * procfs protects read/write of /proc/irq/N/ files against a
22c291ee62SThomas Gleixner * concurrent free of the interrupt descriptor. remove_proc_entry()
23c291ee62SThomas Gleixner * immediately prevents new read/writes to happen and waits for
24c291ee62SThomas Gleixner * already running read/write functions to complete.
25c291ee62SThomas Gleixner *
26c291ee62SThomas Gleixner * We remove the proc entries first and then delete the interrupt
27c291ee62SThomas Gleixner * descriptor from the radix tree and free it. So it is guaranteed
28c291ee62SThomas Gleixner * that irq_to_desc(N) is valid as long as the read/writes are
29c291ee62SThomas Gleixner * permitted by procfs.
30c291ee62SThomas Gleixner *
31c291ee62SThomas Gleixner * The read from /proc/interrupts is a different problem because there
32c291ee62SThomas Gleixner * is no protection. So the lookup and the access to irqdesc
33c291ee62SThomas Gleixner * information must be protected by sparse_irq_lock.
34c291ee62SThomas Gleixner */
354a733ee1SIngo Molnar static struct proc_dir_entry *root_irq_dir;
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds #ifdef CONFIG_SMP
381da177e4SLinus Torvalds
390d3f5425SThomas Gleixner enum {
400d3f5425SThomas Gleixner AFFINITY,
410d3f5425SThomas Gleixner AFFINITY_LIST,
420d3f5425SThomas Gleixner EFFECTIVE,
430d3f5425SThomas Gleixner EFFECTIVE_LIST,
440d3f5425SThomas Gleixner };
450d3f5425SThomas Gleixner
show_irq_affinity(int type,struct seq_file * m)46047dc633SThomas Gleixner static int show_irq_affinity(int type, struct seq_file *m)
471da177e4SLinus Torvalds {
4808678b08SYinghai Lu struct irq_desc *desc = irq_to_desc((long)m->private);
490d3f5425SThomas Gleixner const struct cpumask *mask;
5042ee2b74SAndi Kleen
510d3f5425SThomas Gleixner switch (type) {
520d3f5425SThomas Gleixner case AFFINITY:
530d3f5425SThomas Gleixner case AFFINITY_LIST:
540d3f5425SThomas Gleixner mask = desc->irq_common_data.affinity;
5542ee2b74SAndi Kleen #ifdef CONFIG_GENERIC_PENDING_IRQ
56f230b6d5SThomas Gleixner if (irqd_is_setaffinity_pending(&desc->irq_data))
577f7ace0cSMike Travis mask = desc->pending_mask;
5842ee2b74SAndi Kleen #endif
590d3f5425SThomas Gleixner break;
600d3f5425SThomas Gleixner case EFFECTIVE:
610d3f5425SThomas Gleixner case EFFECTIVE_LIST:
620d3f5425SThomas Gleixner #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
636bc6d4abSMarc Zyngier mask = irq_data_get_effective_affinity_mask(&desc->irq_data);
640d3f5425SThomas Gleixner break;
650d3f5425SThomas Gleixner #endif
66b33394baSThomas Gleixner default:
67b33394baSThomas Gleixner return -EINVAL;
68ce8bdd69Skbuild test robot }
690d3f5425SThomas Gleixner
700d3f5425SThomas Gleixner switch (type) {
710d3f5425SThomas Gleixner case AFFINITY_LIST:
720d3f5425SThomas Gleixner case EFFECTIVE_LIST:
73c1d7f03fSTejun Heo seq_printf(m, "%*pbl\n", cpumask_pr_args(mask));
740d3f5425SThomas Gleixner break;
750d3f5425SThomas Gleixner case AFFINITY:
760d3f5425SThomas Gleixner case EFFECTIVE:
77c1d7f03fSTejun Heo seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
780d3f5425SThomas Gleixner break;
790d3f5425SThomas Gleixner }
80f18e439dSAlexey Dobriyan return 0;
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds
irq_affinity_hint_proc_show(struct seq_file * m,void * v)83e7a297b0SPeter P Waskiewicz Jr static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)
84e7a297b0SPeter P Waskiewicz Jr {
85e7a297b0SPeter P Waskiewicz Jr struct irq_desc *desc = irq_to_desc((long)m->private);
86e7a297b0SPeter P Waskiewicz Jr unsigned long flags;
87e7a297b0SPeter P Waskiewicz Jr cpumask_var_t mask;
88e7a297b0SPeter P Waskiewicz Jr
894308ad80SPeter P Waskiewicz Jr if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
90e7a297b0SPeter P Waskiewicz Jr return -ENOMEM;
91e7a297b0SPeter P Waskiewicz Jr
92e7a297b0SPeter P Waskiewicz Jr raw_spin_lock_irqsave(&desc->lock, flags);
93e7a297b0SPeter P Waskiewicz Jr if (desc->affinity_hint)
94e7a297b0SPeter P Waskiewicz Jr cpumask_copy(mask, desc->affinity_hint);
95e7a297b0SPeter P Waskiewicz Jr raw_spin_unlock_irqrestore(&desc->lock, flags);
96e7a297b0SPeter P Waskiewicz Jr
97c1d7f03fSTejun Heo seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
98e7a297b0SPeter P Waskiewicz Jr free_cpumask_var(mask);
99e7a297b0SPeter P Waskiewicz Jr
100e7a297b0SPeter P Waskiewicz Jr return 0;
101e7a297b0SPeter P Waskiewicz Jr }
102e7a297b0SPeter P Waskiewicz Jr
1031da177e4SLinus Torvalds int no_irq_affinity;
irq_affinity_proc_show(struct seq_file * m,void * v)1044b060420SMike Travis static int irq_affinity_proc_show(struct seq_file *m, void *v)
1054b060420SMike Travis {
1060d3f5425SThomas Gleixner return show_irq_affinity(AFFINITY, m);
1074b060420SMike Travis }
1084b060420SMike Travis
irq_affinity_list_proc_show(struct seq_file * m,void * v)1094b060420SMike Travis static int irq_affinity_list_proc_show(struct seq_file *m, void *v)
1104b060420SMike Travis {
1110d3f5425SThomas Gleixner return show_irq_affinity(AFFINITY_LIST, m);
1124b060420SMike Travis }
1134b060420SMike Travis
114cba6437aSThomas Gleixner #ifndef CONFIG_AUTO_IRQ_AFFINITY
irq_select_affinity_usr(unsigned int irq)115cba6437aSThomas Gleixner static inline int irq_select_affinity_usr(unsigned int irq)
116cba6437aSThomas Gleixner {
117cba6437aSThomas Gleixner /*
118cba6437aSThomas Gleixner * If the interrupt is started up already then this fails. The
119cba6437aSThomas Gleixner * interrupt is assigned to an online CPU already. There is no
120cba6437aSThomas Gleixner * point to move it around randomly. Tell user space that the
121cba6437aSThomas Gleixner * selected mask is bogus.
122cba6437aSThomas Gleixner *
123cba6437aSThomas Gleixner * If not then any change to the affinity is pointless because the
124cba6437aSThomas Gleixner * startup code invokes irq_setup_affinity() which will select
125cba6437aSThomas Gleixner * a online CPU anyway.
126cba6437aSThomas Gleixner */
127cba6437aSThomas Gleixner return -EINVAL;
128cba6437aSThomas Gleixner }
129cba6437aSThomas Gleixner #else
130cba6437aSThomas Gleixner /* ALPHA magic affinity auto selector. Keep it for historical reasons. */
irq_select_affinity_usr(unsigned int irq)131cba6437aSThomas Gleixner static inline int irq_select_affinity_usr(unsigned int irq)
132cba6437aSThomas Gleixner {
133cba6437aSThomas Gleixner return irq_select_affinity(irq);
134cba6437aSThomas Gleixner }
135cba6437aSThomas Gleixner #endif
1364b060420SMike Travis
write_irq_affinity(int type,struct file * file,const char __user * buffer,size_t count,loff_t * pos)1374b060420SMike Travis static ssize_t write_irq_affinity(int type, struct file *file,
138f18e439dSAlexey Dobriyan const char __user *buffer, size_t count, loff_t *pos)
1391da177e4SLinus Torvalds {
140*359745d7SMuchun Song unsigned int irq = (int)(long)pde_data(file_inode(file));
1410de26520SRusty Russell cpumask_var_t new_value;
142f18e439dSAlexey Dobriyan int err;
1431da177e4SLinus Torvalds
1449c255583SThomas Gleixner if (!irq_can_set_affinity_usr(irq) || no_irq_affinity)
1451da177e4SLinus Torvalds return -EIO;
1461da177e4SLinus Torvalds
147c5e3a411STetsuo Handa if (!zalloc_cpumask_var(&new_value, GFP_KERNEL))
1480de26520SRusty Russell return -ENOMEM;
1491da177e4SLinus Torvalds
1504b060420SMike Travis if (type)
1514b060420SMike Travis err = cpumask_parselist_user(buffer, count, new_value);
1524b060420SMike Travis else
1530de26520SRusty Russell err = cpumask_parse_user(buffer, count, new_value);
1540de26520SRusty Russell if (err)
1550de26520SRusty Russell goto free_cpumask;
1560de26520SRusty Russell
1571da177e4SLinus Torvalds /*
1581da177e4SLinus Torvalds * Do not allow disabling IRQs completely - it's a too easy
1591da177e4SLinus Torvalds * way to make the system unusable accidentally :-) At least
1601da177e4SLinus Torvalds * one online CPU still has to be targeted.
1611da177e4SLinus Torvalds */
1620de26520SRusty Russell if (!cpumask_intersects(new_value, cpu_online_mask)) {
163cba4235eSThomas Gleixner /*
164cba4235eSThomas Gleixner * Special case for empty set - allow the architecture code
165cba4235eSThomas Gleixner * to set default SMP affinity.
166cba4235eSThomas Gleixner */
167cba4235eSThomas Gleixner err = irq_select_affinity_usr(irq) ? -EINVAL : count;
1680de26520SRusty Russell } else {
1696714796eSWen Yaxng err = irq_set_affinity(irq, new_value);
1706714796eSWen Yaxng if (!err)
1710de26520SRusty Russell err = count;
1720de26520SRusty Russell }
1731da177e4SLinus Torvalds
1740de26520SRusty Russell free_cpumask:
1750de26520SRusty Russell free_cpumask_var(new_value);
1760de26520SRusty Russell return err;
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds
irq_affinity_proc_write(struct file * file,const char __user * buffer,size_t count,loff_t * pos)1794b060420SMike Travis static ssize_t irq_affinity_proc_write(struct file *file,
1804b060420SMike Travis const char __user *buffer, size_t count, loff_t *pos)
1814b060420SMike Travis {
1824b060420SMike Travis return write_irq_affinity(0, file, buffer, count, pos);
1834b060420SMike Travis }
1844b060420SMike Travis
irq_affinity_list_proc_write(struct file * file,const char __user * buffer,size_t count,loff_t * pos)1854b060420SMike Travis static ssize_t irq_affinity_list_proc_write(struct file *file,
1864b060420SMike Travis const char __user *buffer, size_t count, loff_t *pos)
1874b060420SMike Travis {
1884b060420SMike Travis return write_irq_affinity(1, file, buffer, count, pos);
1894b060420SMike Travis }
1904b060420SMike Travis
irq_affinity_proc_open(struct inode * inode,struct file * file)191f18e439dSAlexey Dobriyan static int irq_affinity_proc_open(struct inode *inode, struct file *file)
19218404756SMax Krasnyansky {
193*359745d7SMuchun Song return single_open(file, irq_affinity_proc_show, pde_data(inode));
19418404756SMax Krasnyansky }
19518404756SMax Krasnyansky
irq_affinity_list_proc_open(struct inode * inode,struct file * file)1964b060420SMike Travis static int irq_affinity_list_proc_open(struct inode *inode, struct file *file)
1974b060420SMike Travis {
198*359745d7SMuchun Song return single_open(file, irq_affinity_list_proc_show, pde_data(inode));
1994b060420SMike Travis }
2004b060420SMike Travis
20197a32539SAlexey Dobriyan static const struct proc_ops irq_affinity_proc_ops = {
20297a32539SAlexey Dobriyan .proc_open = irq_affinity_proc_open,
20397a32539SAlexey Dobriyan .proc_read = seq_read,
20497a32539SAlexey Dobriyan .proc_lseek = seq_lseek,
20597a32539SAlexey Dobriyan .proc_release = single_release,
20697a32539SAlexey Dobriyan .proc_write = irq_affinity_proc_write,
207f18e439dSAlexey Dobriyan };
208f18e439dSAlexey Dobriyan
20997a32539SAlexey Dobriyan static const struct proc_ops irq_affinity_list_proc_ops = {
21097a32539SAlexey Dobriyan .proc_open = irq_affinity_list_proc_open,
21197a32539SAlexey Dobriyan .proc_read = seq_read,
21297a32539SAlexey Dobriyan .proc_lseek = seq_lseek,
21397a32539SAlexey Dobriyan .proc_release = single_release,
21497a32539SAlexey Dobriyan .proc_write = irq_affinity_list_proc_write,
2154b060420SMike Travis };
2164b060420SMike Travis
2170d3f5425SThomas Gleixner #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
irq_effective_aff_proc_show(struct seq_file * m,void * v)2180d3f5425SThomas Gleixner static int irq_effective_aff_proc_show(struct seq_file *m, void *v)
2190d3f5425SThomas Gleixner {
2200d3f5425SThomas Gleixner return show_irq_affinity(EFFECTIVE, m);
2210d3f5425SThomas Gleixner }
2220d3f5425SThomas Gleixner
irq_effective_aff_list_proc_show(struct seq_file * m,void * v)2230d3f5425SThomas Gleixner static int irq_effective_aff_list_proc_show(struct seq_file *m, void *v)
2240d3f5425SThomas Gleixner {
2250d3f5425SThomas Gleixner return show_irq_affinity(EFFECTIVE_LIST, m);
2260d3f5425SThomas Gleixner }
2270d3f5425SThomas Gleixner #endif
2280d3f5425SThomas Gleixner
default_affinity_show(struct seq_file * m,void * v)229f18e439dSAlexey Dobriyan static int default_affinity_show(struct seq_file *m, void *v)
23018404756SMax Krasnyansky {
231c1d7f03fSTejun Heo seq_printf(m, "%*pb\n", cpumask_pr_args(irq_default_affinity));
232f18e439dSAlexey Dobriyan return 0;
233f18e439dSAlexey Dobriyan }
234f18e439dSAlexey Dobriyan
default_affinity_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)235f18e439dSAlexey Dobriyan static ssize_t default_affinity_write(struct file *file,
236f18e439dSAlexey Dobriyan const char __user *buffer, size_t count, loff_t *ppos)
237f18e439dSAlexey Dobriyan {
238d036e67bSRusty Russell cpumask_var_t new_value;
239f18e439dSAlexey Dobriyan int err;
24018404756SMax Krasnyansky
241c5e3a411STetsuo Handa if (!zalloc_cpumask_var(&new_value, GFP_KERNEL))
242d036e67bSRusty Russell return -ENOMEM;
24318404756SMax Krasnyansky
244d036e67bSRusty Russell err = cpumask_parse_user(buffer, count, new_value);
245d036e67bSRusty Russell if (err)
246d036e67bSRusty Russell goto out;
247d036e67bSRusty Russell
24818404756SMax Krasnyansky /*
24918404756SMax Krasnyansky * Do not allow disabling IRQs completely - it's a too easy
25018404756SMax Krasnyansky * way to make the system unusable accidentally :-) At least
25118404756SMax Krasnyansky * one online CPU still has to be targeted.
25218404756SMax Krasnyansky */
253d036e67bSRusty Russell if (!cpumask_intersects(new_value, cpu_online_mask)) {
254d036e67bSRusty Russell err = -EINVAL;
255d036e67bSRusty Russell goto out;
256d036e67bSRusty Russell }
25718404756SMax Krasnyansky
258d036e67bSRusty Russell cpumask_copy(irq_default_affinity, new_value);
259d036e67bSRusty Russell err = count;
26018404756SMax Krasnyansky
261d036e67bSRusty Russell out:
262d036e67bSRusty Russell free_cpumask_var(new_value);
263d036e67bSRusty Russell return err;
26418404756SMax Krasnyansky }
265f18e439dSAlexey Dobriyan
default_affinity_open(struct inode * inode,struct file * file)266f18e439dSAlexey Dobriyan static int default_affinity_open(struct inode *inode, struct file *file)
267f18e439dSAlexey Dobriyan {
268*359745d7SMuchun Song return single_open(file, default_affinity_show, pde_data(inode));
269f18e439dSAlexey Dobriyan }
270f18e439dSAlexey Dobriyan
27197a32539SAlexey Dobriyan static const struct proc_ops default_affinity_proc_ops = {
27297a32539SAlexey Dobriyan .proc_open = default_affinity_open,
27397a32539SAlexey Dobriyan .proc_read = seq_read,
27497a32539SAlexey Dobriyan .proc_lseek = seq_lseek,
27597a32539SAlexey Dobriyan .proc_release = single_release,
27697a32539SAlexey Dobriyan .proc_write = default_affinity_write,
277f18e439dSAlexey Dobriyan };
27892d6b71aSDimitri Sivanich
irq_node_proc_show(struct seq_file * m,void * v)27992d6b71aSDimitri Sivanich static int irq_node_proc_show(struct seq_file *m, void *v)
28092d6b71aSDimitri Sivanich {
28192d6b71aSDimitri Sivanich struct irq_desc *desc = irq_to_desc((long) m->private);
28292d6b71aSDimitri Sivanich
2836783011bSJiang Liu seq_printf(m, "%d\n", irq_desc_get_node(desc));
28492d6b71aSDimitri Sivanich return 0;
28592d6b71aSDimitri Sivanich }
2861da177e4SLinus Torvalds #endif
2871da177e4SLinus Torvalds
irq_spurious_proc_show(struct seq_file * m,void * v)288a1afb637SAlexey Dobriyan static int irq_spurious_proc_show(struct seq_file *m, void *v)
28996d97cf0SAndi Kleen {
290a1afb637SAlexey Dobriyan struct irq_desc *desc = irq_to_desc((long) m->private);
291a1afb637SAlexey Dobriyan
292a1afb637SAlexey Dobriyan seq_printf(m, "count %u\n" "unhandled %u\n" "last_unhandled %u ms\n",
293a1afb637SAlexey Dobriyan desc->irq_count, desc->irqs_unhandled,
29408678b08SYinghai Lu jiffies_to_msecs(desc->last_unhandled));
295a1afb637SAlexey Dobriyan return 0;
29696d97cf0SAndi Kleen }
29796d97cf0SAndi Kleen
2981da177e4SLinus Torvalds #define MAX_NAMELEN 128
2991da177e4SLinus Torvalds
name_unique(unsigned int irq,struct irqaction * new_action)3001da177e4SLinus Torvalds static int name_unique(unsigned int irq, struct irqaction *new_action)
3011da177e4SLinus Torvalds {
30208678b08SYinghai Lu struct irq_desc *desc = irq_to_desc(irq);
3031da177e4SLinus Torvalds struct irqaction *action;
304d2d9433aSDmitry Adamushko unsigned long flags;
305d2d9433aSDmitry Adamushko int ret = 1;
3061da177e4SLinus Torvalds
307239007b8SThomas Gleixner raw_spin_lock_irqsave(&desc->lock, flags);
308f944b5a7SDaniel Lezcano for_each_action_of_desc(desc, action) {
3091da177e4SLinus Torvalds if ((action != new_action) && action->name &&
310d2d9433aSDmitry Adamushko !strcmp(new_action->name, action->name)) {
311d2d9433aSDmitry Adamushko ret = 0;
312d2d9433aSDmitry Adamushko break;
313d2d9433aSDmitry Adamushko }
314d2d9433aSDmitry Adamushko }
315239007b8SThomas Gleixner raw_spin_unlock_irqrestore(&desc->lock, flags);
316d2d9433aSDmitry Adamushko return ret;
3171da177e4SLinus Torvalds }
3181da177e4SLinus Torvalds
register_handler_proc(unsigned int irq,struct irqaction * action)3191da177e4SLinus Torvalds void register_handler_proc(unsigned int irq, struct irqaction *action)
3201da177e4SLinus Torvalds {
3211da177e4SLinus Torvalds char name [MAX_NAMELEN];
32208678b08SYinghai Lu struct irq_desc *desc = irq_to_desc(irq);
3231da177e4SLinus Torvalds
32408678b08SYinghai Lu if (!desc->dir || action->dir || !action->name ||
3251da177e4SLinus Torvalds !name_unique(irq, action))
3261da177e4SLinus Torvalds return;
3271da177e4SLinus Torvalds
3281da177e4SLinus Torvalds snprintf(name, MAX_NAMELEN, "%s", action->name);
3291da177e4SLinus Torvalds
3301da177e4SLinus Torvalds /* create /proc/irq/1234/handler/ */
33108678b08SYinghai Lu action->dir = proc_mkdir(name, desc->dir);
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds
3341da177e4SLinus Torvalds #undef MAX_NAMELEN
3351da177e4SLinus Torvalds
3361da177e4SLinus Torvalds #define MAX_NAMELEN 10
3371da177e4SLinus Torvalds
register_irq_proc(unsigned int irq,struct irq_desc * desc)3382c6927a3SYinghai Lu void register_irq_proc(unsigned int irq, struct irq_desc *desc)
3391da177e4SLinus Torvalds {
34095c2b175SBen Hutchings static DEFINE_MUTEX(register_lock);
341c1a80386SThomas Gleixner void __maybe_unused *irqp = (void *)(unsigned long) irq;
3421da177e4SLinus Torvalds char name [MAX_NAMELEN];
3431da177e4SLinus Torvalds
34495c2b175SBen Hutchings if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
3451da177e4SLinus Torvalds return;
3461da177e4SLinus Torvalds
34795c2b175SBen Hutchings /*
34895c2b175SBen Hutchings * irq directories are registered only when a handler is
34995c2b175SBen Hutchings * added, not when the descriptor is created, so multiple
35095c2b175SBen Hutchings * tasks might try to register at the same time.
35195c2b175SBen Hutchings */
35295c2b175SBen Hutchings mutex_lock(®ister_lock);
35395c2b175SBen Hutchings
35495c2b175SBen Hutchings if (desc->dir)
35595c2b175SBen Hutchings goto out_unlock;
35695c2b175SBen Hutchings
3571da177e4SLinus Torvalds sprintf(name, "%d", irq);
3581da177e4SLinus Torvalds
3591da177e4SLinus Torvalds /* create /proc/irq/1234 */
36008678b08SYinghai Lu desc->dir = proc_mkdir(name, root_irq_dir);
361c82a43d4SCyrill Gorcunov if (!desc->dir)
36295c2b175SBen Hutchings goto out_unlock;
3631da177e4SLinus Torvalds
3641da177e4SLinus Torvalds #ifdef CONFIG_SMP
3651da177e4SLinus Torvalds /* create /proc/irq/<irq>/smp_affinity */
366bab5c790SChema Gonzalez proc_create_data("smp_affinity", 0644, desc->dir,
36797a32539SAlexey Dobriyan &irq_affinity_proc_ops, irqp);
36892d6b71aSDimitri Sivanich
369e7a297b0SPeter P Waskiewicz Jr /* create /proc/irq/<irq>/affinity_hint */
3703f3942acSChristoph Hellwig proc_create_single_data("affinity_hint", 0444, desc->dir,
3713f3942acSChristoph Hellwig irq_affinity_hint_proc_show, irqp);
372e7a297b0SPeter P Waskiewicz Jr
3734b060420SMike Travis /* create /proc/irq/<irq>/smp_affinity_list */
374bab5c790SChema Gonzalez proc_create_data("smp_affinity_list", 0644, desc->dir,
37597a32539SAlexey Dobriyan &irq_affinity_list_proc_ops, irqp);
3764b060420SMike Travis
3773f3942acSChristoph Hellwig proc_create_single_data("node", 0444, desc->dir, irq_node_proc_show,
3783f3942acSChristoph Hellwig irqp);
3790d3f5425SThomas Gleixner # ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
3803f3942acSChristoph Hellwig proc_create_single_data("effective_affinity", 0444, desc->dir,
3813f3942acSChristoph Hellwig irq_effective_aff_proc_show, irqp);
3823f3942acSChristoph Hellwig proc_create_single_data("effective_affinity_list", 0444, desc->dir,
3833f3942acSChristoph Hellwig irq_effective_aff_list_proc_show, irqp);
3840d3f5425SThomas Gleixner # endif
3851da177e4SLinus Torvalds #endif
3863f3942acSChristoph Hellwig proc_create_single_data("spurious", 0444, desc->dir,
3873f3942acSChristoph Hellwig irq_spurious_proc_show, (void *)(long)irq);
38895c2b175SBen Hutchings
38995c2b175SBen Hutchings out_unlock:
39095c2b175SBen Hutchings mutex_unlock(®ister_lock);
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds
unregister_irq_proc(unsigned int irq,struct irq_desc * desc)39313bfe99eSThomas Gleixner void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)
39413bfe99eSThomas Gleixner {
39513bfe99eSThomas Gleixner char name [MAX_NAMELEN];
39613bfe99eSThomas Gleixner
39713bfe99eSThomas Gleixner if (!root_irq_dir || !desc->dir)
39813bfe99eSThomas Gleixner return;
39913bfe99eSThomas Gleixner #ifdef CONFIG_SMP
40013bfe99eSThomas Gleixner remove_proc_entry("smp_affinity", desc->dir);
40113bfe99eSThomas Gleixner remove_proc_entry("affinity_hint", desc->dir);
402def945eeSYinghai Lu remove_proc_entry("smp_affinity_list", desc->dir);
40313bfe99eSThomas Gleixner remove_proc_entry("node", desc->dir);
4040d3f5425SThomas Gleixner # ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
4050d3f5425SThomas Gleixner remove_proc_entry("effective_affinity", desc->dir);
4060d3f5425SThomas Gleixner remove_proc_entry("effective_affinity_list", desc->dir);
4070d3f5425SThomas Gleixner # endif
40813bfe99eSThomas Gleixner #endif
40913bfe99eSThomas Gleixner remove_proc_entry("spurious", desc->dir);
41013bfe99eSThomas Gleixner
41113bfe99eSThomas Gleixner sprintf(name, "%u", irq);
41213bfe99eSThomas Gleixner remove_proc_entry(name, root_irq_dir);
41313bfe99eSThomas Gleixner }
41413bfe99eSThomas Gleixner
4151da177e4SLinus Torvalds #undef MAX_NAMELEN
4161da177e4SLinus Torvalds
unregister_handler_proc(unsigned int irq,struct irqaction * action)4171da177e4SLinus Torvalds void unregister_handler_proc(unsigned int irq, struct irqaction *action)
4181da177e4SLinus Torvalds {
419a8ca16eaSDavid Howells proc_remove(action->dir);
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds
register_default_affinity_proc(void)4223786fc71Sroel kluin static void register_default_affinity_proc(void)
42318404756SMax Krasnyansky {
42418404756SMax Krasnyansky #ifdef CONFIG_SMP
425bab5c790SChema Gonzalez proc_create("irq/default_smp_affinity", 0644, NULL,
42697a32539SAlexey Dobriyan &default_affinity_proc_ops);
42718404756SMax Krasnyansky #endif
42818404756SMax Krasnyansky }
42918404756SMax Krasnyansky
init_irq_proc(void)4301da177e4SLinus Torvalds void init_irq_proc(void)
4311da177e4SLinus Torvalds {
4322c6927a3SYinghai Lu unsigned int irq;
4332c6927a3SYinghai Lu struct irq_desc *desc;
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds /* create /proc/irq */
4361da177e4SLinus Torvalds root_irq_dir = proc_mkdir("irq", NULL);
4371da177e4SLinus Torvalds if (!root_irq_dir)
4381da177e4SLinus Torvalds return;
4391da177e4SLinus Torvalds
44018404756SMax Krasnyansky register_default_affinity_proc();
44118404756SMax Krasnyansky
4421da177e4SLinus Torvalds /*
4431da177e4SLinus Torvalds * Create entries for all existing IRQs.
4441da177e4SLinus Torvalds */
445fe3464caSJianyu Zhan for_each_irq_desc(irq, desc)
4462c6927a3SYinghai Lu register_irq_proc(irq, desc);
4471da177e4SLinus Torvalds }
4481da177e4SLinus Torvalds
449c78b9b65SThomas Gleixner #ifdef CONFIG_GENERIC_IRQ_SHOW
450c78b9b65SThomas Gleixner
arch_show_interrupts(struct seq_file * p,int prec)451c78b9b65SThomas Gleixner int __weak arch_show_interrupts(struct seq_file *p, int prec)
452c78b9b65SThomas Gleixner {
453c78b9b65SThomas Gleixner return 0;
454c78b9b65SThomas Gleixner }
455c78b9b65SThomas Gleixner
456a6e120edSThomas Gleixner #ifndef ACTUAL_NR_IRQS
457a6e120edSThomas Gleixner # define ACTUAL_NR_IRQS nr_irqs
458a6e120edSThomas Gleixner #endif
459a6e120edSThomas Gleixner
show_interrupts(struct seq_file * p,void * v)460c78b9b65SThomas Gleixner int show_interrupts(struct seq_file *p, void *v)
461c78b9b65SThomas Gleixner {
462c78b9b65SThomas Gleixner static int prec;
463c78b9b65SThomas Gleixner
464c78b9b65SThomas Gleixner unsigned long flags, any_count = 0;
465c78b9b65SThomas Gleixner int i = *(loff_t *) v, j;
466c78b9b65SThomas Gleixner struct irqaction *action;
467c78b9b65SThomas Gleixner struct irq_desc *desc;
468c78b9b65SThomas Gleixner
469a6e120edSThomas Gleixner if (i > ACTUAL_NR_IRQS)
470c78b9b65SThomas Gleixner return 0;
471c78b9b65SThomas Gleixner
472a6e120edSThomas Gleixner if (i == ACTUAL_NR_IRQS)
473c78b9b65SThomas Gleixner return arch_show_interrupts(p, prec);
474c78b9b65SThomas Gleixner
475c78b9b65SThomas Gleixner /* print header and calculate the width of the first column */
476c78b9b65SThomas Gleixner if (i == 0) {
477c78b9b65SThomas Gleixner for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
478c78b9b65SThomas Gleixner j *= 10;
479c78b9b65SThomas Gleixner
480c78b9b65SThomas Gleixner seq_printf(p, "%*s", prec + 8, "");
481c78b9b65SThomas Gleixner for_each_online_cpu(j)
482c78b9b65SThomas Gleixner seq_printf(p, "CPU%-8d", j);
483c78b9b65SThomas Gleixner seq_putc(p, '\n');
484c78b9b65SThomas Gleixner }
485c78b9b65SThomas Gleixner
48674bdf781SEric Dumazet rcu_read_lock();
487c78b9b65SThomas Gleixner desc = irq_to_desc(i);
48883cfac95SMarc Zyngier if (!desc || irq_settings_is_hidden(desc))
489c291ee62SThomas Gleixner goto outsparse;
490c78b9b65SThomas Gleixner
4919e42ad10SThomas Gleixner if (desc->kstat_irqs) {
492c78b9b65SThomas Gleixner for_each_online_cpu(j)
4939e42ad10SThomas Gleixner any_count |= data_race(*per_cpu_ptr(desc->kstat_irqs, j));
4949e42ad10SThomas Gleixner }
49574bdf781SEric Dumazet
49674bdf781SEric Dumazet if ((!desc->action || irq_desc_is_chained(desc)) && !any_count)
49774bdf781SEric Dumazet goto outsparse;
498c78b9b65SThomas Gleixner
499c78b9b65SThomas Gleixner seq_printf(p, "%*d: ", prec, i);
500c78b9b65SThomas Gleixner for_each_online_cpu(j)
50174bdf781SEric Dumazet seq_printf(p, "%10u ", desc->kstat_irqs ?
50274bdf781SEric Dumazet *per_cpu_ptr(desc->kstat_irqs, j) : 0);
503ab7798ffSThomas Gleixner
50474bdf781SEric Dumazet raw_spin_lock_irqsave(&desc->lock, flags);
505ab7798ffSThomas Gleixner if (desc->irq_data.chip) {
506ab7798ffSThomas Gleixner if (desc->irq_data.chip->irq_print_chip)
507ab7798ffSThomas Gleixner desc->irq_data.chip->irq_print_chip(&desc->irq_data, p);
508ab7798ffSThomas Gleixner else if (desc->irq_data.chip->name)
509c78b9b65SThomas Gleixner seq_printf(p, " %8s", desc->irq_data.chip->name);
510ab7798ffSThomas Gleixner else
511ab7798ffSThomas Gleixner seq_printf(p, " %8s", "-");
512ab7798ffSThomas Gleixner } else {
513ab7798ffSThomas Gleixner seq_printf(p, " %8s", "None");
514ab7798ffSThomas Gleixner }
515c12d2f42SGrant Likely if (desc->irq_data.domain)
516d92df42dSCédric Le Goater seq_printf(p, " %*lu", prec, desc->irq_data.hwirq);
517f435da41SH Hartley Sweeten else
518f435da41SH Hartley Sweeten seq_printf(p, " %*s", prec, "");
51994b2c363SGeert Uytterhoeven #ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
520ab7798ffSThomas Gleixner seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
521ab7798ffSThomas Gleixner #endif
522ee0401ecSThomas Gleixner if (desc->name)
523c78b9b65SThomas Gleixner seq_printf(p, "-%-8s", desc->name);
524c78b9b65SThomas Gleixner
52574bdf781SEric Dumazet action = desc->action;
526c78b9b65SThomas Gleixner if (action) {
527c78b9b65SThomas Gleixner seq_printf(p, " %s", action->name);
528c78b9b65SThomas Gleixner while ((action = action->next) != NULL)
529c78b9b65SThomas Gleixner seq_printf(p, ", %s", action->name);
530c78b9b65SThomas Gleixner }
531c78b9b65SThomas Gleixner
532c78b9b65SThomas Gleixner seq_putc(p, '\n');
533c78b9b65SThomas Gleixner raw_spin_unlock_irqrestore(&desc->lock, flags);
534c291ee62SThomas Gleixner outsparse:
53574bdf781SEric Dumazet rcu_read_unlock();
536c78b9b65SThomas Gleixner return 0;
537c78b9b65SThomas Gleixner }
538c78b9b65SThomas Gleixner #endif
539