~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/irq/proc.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
  4  *
  5  * This file contains the /proc/irq/ handling code.
  6  */
  7 
  8 #include <linux/irq.h>
  9 #include <linux/gfp.h>
 10 #include <linux/proc_fs.h>
 11 #include <linux/seq_file.h>
 12 #include <linux/interrupt.h>
 13 #include <linux/kernel_stat.h>
 14 #include <linux/mutex.h>
 15 
 16 #include "internals.h"
 17 
 18 /*
 19  * Access rules:
 20  *
 21  * procfs protects read/write of /proc/irq/N/ files against a
 22  * concurrent free of the interrupt descriptor. remove_proc_entry()
 23  * immediately prevents new read/writes to happen and waits for
 24  * already running read/write functions to complete.
 25  *
 26  * We remove the proc entries first and then delete the interrupt
 27  * descriptor from the radix tree and free it. So it is guaranteed
 28  * that irq_to_desc(N) is valid as long as the read/writes are
 29  * permitted by procfs.
 30  *
 31  * The read from /proc/interrupts is a different problem because there
 32  * is no protection. So the lookup and the access to irqdesc
 33  * information must be protected by sparse_irq_lock.
 34  */
 35 static struct proc_dir_entry *root_irq_dir;
 36 
 37 #ifdef CONFIG_SMP
 38 
 39 enum {
 40         AFFINITY,
 41         AFFINITY_LIST,
 42         EFFECTIVE,
 43         EFFECTIVE_LIST,
 44 };
 45 
 46 static int show_irq_affinity(int type, struct seq_file *m)
 47 {
 48         struct irq_desc *desc = irq_to_desc((long)m->private);
 49         const struct cpumask *mask;
 50 
 51         switch (type) {
 52         case AFFINITY:
 53         case AFFINITY_LIST:
 54                 mask = desc->irq_common_data.affinity;
 55 #ifdef CONFIG_GENERIC_PENDING_IRQ
 56                 if (irqd_is_setaffinity_pending(&desc->irq_data))
 57                         mask = desc->pending_mask;
 58 #endif
 59                 break;
 60         case EFFECTIVE:
 61         case EFFECTIVE_LIST:
 62 #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
 63                 mask = irq_data_get_effective_affinity_mask(&desc->irq_data);
 64                 break;
 65 #endif
 66         default:
 67                 return -EINVAL;
 68         }
 69 
 70         switch (type) {
 71         case AFFINITY_LIST:
 72         case EFFECTIVE_LIST:
 73                 seq_printf(m, "%*pbl\n", cpumask_pr_args(mask));
 74                 break;
 75         case AFFINITY:
 76         case EFFECTIVE:
 77                 seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
 78                 break;
 79         }
 80         return 0;
 81 }
 82 
 83 static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)
 84 {
 85         struct irq_desc *desc = irq_to_desc((long)m->private);
 86         unsigned long flags;
 87         cpumask_var_t mask;
 88 
 89         if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
 90                 return -ENOMEM;
 91 
 92         raw_spin_lock_irqsave(&desc->lock, flags);
 93         if (desc->affinity_hint)
 94                 cpumask_copy(mask, desc->affinity_hint);
 95         raw_spin_unlock_irqrestore(&desc->lock, flags);
 96 
 97         seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
 98         free_cpumask_var(mask);
 99 
100         return 0;
101 }
102 
103 int no_irq_affinity;
104 static int irq_affinity_proc_show(struct seq_file *m, void *v)
105 {
106         return show_irq_affinity(AFFINITY, m);
107 }
108 
109 static int irq_affinity_list_proc_show(struct seq_file *m, void *v)
110 {
111         return show_irq_affinity(AFFINITY_LIST, m);
112 }
113 
114 #ifndef CONFIG_AUTO_IRQ_AFFINITY
115 static inline int irq_select_affinity_usr(unsigned int irq)
116 {
117         /*
118          * If the interrupt is started up already then this fails. The
119          * interrupt is assigned to an online CPU already. There is no
120          * point to move it around randomly. Tell user space that the
121          * selected mask is bogus.
122          *
123          * If not then any change to the affinity is pointless because the
124          * startup code invokes irq_setup_affinity() which will select
125          * a online CPU anyway.
126          */
127         return -EINVAL;
128 }
129 #else
130 /* ALPHA magic affinity auto selector. Keep it for historical reasons. */
131 static inline int irq_select_affinity_usr(unsigned int irq)
132 {
133         return irq_select_affinity(irq);
134 }
135 #endif
136 
137 static ssize_t write_irq_affinity(int type, struct file *file,
138                 const char __user *buffer, size_t count, loff_t *pos)
139 {
140         unsigned int irq = (int)(long)pde_data(file_inode(file));
141         cpumask_var_t new_value;
142         int err;
143 
144         if (!irq_can_set_affinity_usr(irq) || no_irq_affinity)
145                 return -EIO;
146 
147         if (!zalloc_cpumask_var(&new_value, GFP_KERNEL))
148                 return -ENOMEM;
149 
150         if (type)
151                 err = cpumask_parselist_user(buffer, count, new_value);
152         else
153                 err = cpumask_parse_user(buffer, count, new_value);
154         if (err)
155                 goto free_cpumask;
156 
157         /*
158          * Do not allow disabling IRQs completely - it's a too easy
159          * way to make the system unusable accidentally :-) At least
160          * one online CPU still has to be targeted.
161          */
162         if (!cpumask_intersects(new_value, cpu_online_mask)) {
163                 /*
164                  * Special case for empty set - allow the architecture code
165                  * to set default SMP affinity.
166                  */
167                 err = irq_select_affinity_usr(irq) ? -EINVAL : count;
168         } else {
169                 err = irq_set_affinity(irq, new_value);
170                 if (!err)
171                         err = count;
172         }
173 
174 free_cpumask:
175         free_cpumask_var(new_value);
176         return err;
177 }
178 
179 static ssize_t irq_affinity_proc_write(struct file *file,
180                 const char __user *buffer, size_t count, loff_t *pos)
181 {
182         return write_irq_affinity(0, file, buffer, count, pos);
183 }
184 
185 static ssize_t irq_affinity_list_proc_write(struct file *file,
186                 const char __user *buffer, size_t count, loff_t *pos)
187 {
188         return write_irq_affinity(1, file, buffer, count, pos);
189 }
190 
191 static int irq_affinity_proc_open(struct inode *inode, struct file *file)
192 {
193         return single_open(file, irq_affinity_proc_show, pde_data(inode));
194 }
195 
196 static int irq_affinity_list_proc_open(struct inode *inode, struct file *file)
197 {
198         return single_open(file, irq_affinity_list_proc_show, pde_data(inode));
199 }
200 
201 static const struct proc_ops irq_affinity_proc_ops = {
202         .proc_open      = irq_affinity_proc_open,
203         .proc_read      = seq_read,
204         .proc_lseek     = seq_lseek,
205         .proc_release   = single_release,
206         .proc_write     = irq_affinity_proc_write,
207 };
208 
209 static const struct proc_ops irq_affinity_list_proc_ops = {
210         .proc_open      = irq_affinity_list_proc_open,
211         .proc_read      = seq_read,
212         .proc_lseek     = seq_lseek,
213         .proc_release   = single_release,
214         .proc_write     = irq_affinity_list_proc_write,
215 };
216 
217 #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
218 static int irq_effective_aff_proc_show(struct seq_file *m, void *v)
219 {
220         return show_irq_affinity(EFFECTIVE, m);
221 }
222 
223 static int irq_effective_aff_list_proc_show(struct seq_file *m, void *v)
224 {
225         return show_irq_affinity(EFFECTIVE_LIST, m);
226 }
227 #endif
228 
229 static int default_affinity_show(struct seq_file *m, void *v)
230 {
231         seq_printf(m, "%*pb\n", cpumask_pr_args(irq_default_affinity));
232         return 0;
233 }
234 
235 static ssize_t default_affinity_write(struct file *file,
236                 const char __user *buffer, size_t count, loff_t *ppos)
237 {
238         cpumask_var_t new_value;
239         int err;
240 
241         if (!zalloc_cpumask_var(&new_value, GFP_KERNEL))
242                 return -ENOMEM;
243 
244         err = cpumask_parse_user(buffer, count, new_value);
245         if (err)
246                 goto out;
247 
248         /*
249          * Do not allow disabling IRQs completely - it's a too easy
250          * way to make the system unusable accidentally :-) At least
251          * one online CPU still has to be targeted.
252          */
253         if (!cpumask_intersects(new_value, cpu_online_mask)) {
254                 err = -EINVAL;
255                 goto out;
256         }
257 
258         cpumask_copy(irq_default_affinity, new_value);
259         err = count;
260 
261 out:
262         free_cpumask_var(new_value);
263         return err;
264 }
265 
266 static int default_affinity_open(struct inode *inode, struct file *file)
267 {
268         return single_open(file, default_affinity_show, pde_data(inode));
269 }
270 
271 static const struct proc_ops default_affinity_proc_ops = {
272         .proc_open      = default_affinity_open,
273         .proc_read      = seq_read,
274         .proc_lseek     = seq_lseek,
275         .proc_release   = single_release,
276         .proc_write     = default_affinity_write,
277 };
278 
279 static int irq_node_proc_show(struct seq_file *m, void *v)
280 {
281         struct irq_desc *desc = irq_to_desc((long) m->private);
282 
283         seq_printf(m, "%d\n", irq_desc_get_node(desc));
284         return 0;
285 }
286 #endif
287 
288 static int irq_spurious_proc_show(struct seq_file *m, void *v)
289 {
290         struct irq_desc *desc = irq_to_desc((long) m->private);
291 
292         seq_printf(m, "count %u\n" "unhandled %u\n" "last_unhandled %u ms\n",
293                    desc->irq_count, desc->irqs_unhandled,
294                    jiffies_to_msecs(desc->last_unhandled));
295         return 0;
296 }
297 
298 #define MAX_NAMELEN 128
299 
300 static int name_unique(unsigned int irq, struct irqaction *new_action)
301 {
302         struct irq_desc *desc = irq_to_desc(irq);
303         struct irqaction *action;
304         unsigned long flags;
305         int ret = 1;
306 
307         raw_spin_lock_irqsave(&desc->lock, flags);
308         for_each_action_of_desc(desc, action) {
309                 if ((action != new_action) && action->name &&
310                                 !strcmp(new_action->name, action->name)) {
311                         ret = 0;
312                         break;
313                 }
314         }
315         raw_spin_unlock_irqrestore(&desc->lock, flags);
316         return ret;
317 }
318 
319 void register_handler_proc(unsigned int irq, struct irqaction *action)
320 {
321         char name [MAX_NAMELEN];
322         struct irq_desc *desc = irq_to_desc(irq);
323 
324         if (!desc->dir || action->dir || !action->name ||
325                                         !name_unique(irq, action))
326                 return;
327 
328         snprintf(name, MAX_NAMELEN, "%s", action->name);
329 
330         /* create /proc/irq/1234/handler/ */
331         action->dir = proc_mkdir(name, desc->dir);
332 }
333 
334 #undef MAX_NAMELEN
335 
336 #define MAX_NAMELEN 10
337 
338 void register_irq_proc(unsigned int irq, struct irq_desc *desc)
339 {
340         static DEFINE_MUTEX(register_lock);
341         void __maybe_unused *irqp = (void *)(unsigned long) irq;
342         char name [MAX_NAMELEN];
343 
344         if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
345                 return;
346 
347         /*
348          * irq directories are registered only when a handler is
349          * added, not when the descriptor is created, so multiple
350          * tasks might try to register at the same time.
351          */
352         mutex_lock(&register_lock);
353 
354         if (desc->dir)
355                 goto out_unlock;
356 
357         sprintf(name, "%d", irq);
358 
359         /* create /proc/irq/1234 */
360         desc->dir = proc_mkdir(name, root_irq_dir);
361         if (!desc->dir)
362                 goto out_unlock;
363 
364 #ifdef CONFIG_SMP
365         /* create /proc/irq/<irq>/smp_affinity */
366         proc_create_data("smp_affinity", 0644, desc->dir,
367                          &irq_affinity_proc_ops, irqp);
368 
369         /* create /proc/irq/<irq>/affinity_hint */
370         proc_create_single_data("affinity_hint", 0444, desc->dir,
371                         irq_affinity_hint_proc_show, irqp);
372 
373         /* create /proc/irq/<irq>/smp_affinity_list */
374         proc_create_data("smp_affinity_list", 0644, desc->dir,
375                          &irq_affinity_list_proc_ops, irqp);
376 
377         proc_create_single_data("node", 0444, desc->dir, irq_node_proc_show,
378                         irqp);
379 # ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
380         proc_create_single_data("effective_affinity", 0444, desc->dir,
381                         irq_effective_aff_proc_show, irqp);
382         proc_create_single_data("effective_affinity_list", 0444, desc->dir,
383                         irq_effective_aff_list_proc_show, irqp);
384 # endif
385 #endif
386         proc_create_single_data("spurious", 0444, desc->dir,
387                         irq_spurious_proc_show, (void *)(long)irq);
388 
389 out_unlock:
390         mutex_unlock(&register_lock);
391 }
392 
393 void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)
394 {
395         char name [MAX_NAMELEN];
396 
397         if (!root_irq_dir || !desc->dir)
398                 return;
399 #ifdef CONFIG_SMP
400         remove_proc_entry("smp_affinity", desc->dir);
401         remove_proc_entry("affinity_hint", desc->dir);
402         remove_proc_entry("smp_affinity_list", desc->dir);
403         remove_proc_entry("node", desc->dir);
404 # ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
405         remove_proc_entry("effective_affinity", desc->dir);
406         remove_proc_entry("effective_affinity_list", desc->dir);
407 # endif
408 #endif
409         remove_proc_entry("spurious", desc->dir);
410 
411         sprintf(name, "%u", irq);
412         remove_proc_entry(name, root_irq_dir);
413 }
414 
415 #undef MAX_NAMELEN
416 
417 void unregister_handler_proc(unsigned int irq, struct irqaction *action)
418 {
419         proc_remove(action->dir);
420 }
421 
422 static void register_default_affinity_proc(void)
423 {
424 #ifdef CONFIG_SMP
425         proc_create("irq/default_smp_affinity", 0644, NULL,
426                     &default_affinity_proc_ops);
427 #endif
428 }
429 
430 void init_irq_proc(void)
431 {
432         unsigned int irq;
433         struct irq_desc *desc;
434 
435         /* create /proc/irq */
436         root_irq_dir = proc_mkdir("irq", NULL);
437         if (!root_irq_dir)
438                 return;
439 
440         register_default_affinity_proc();
441 
442         /*
443          * Create entries for all existing IRQs.
444          */
445         for_each_irq_desc(irq, desc)
446                 register_irq_proc(irq, desc);
447 }
448 
449 #ifdef CONFIG_GENERIC_IRQ_SHOW
450 
451 int __weak arch_show_interrupts(struct seq_file *p, int prec)
452 {
453         return 0;
454 }
455 
456 #ifndef ACTUAL_NR_IRQS
457 # define ACTUAL_NR_IRQS nr_irqs
458 #endif
459 
460 int show_interrupts(struct seq_file *p, void *v)
461 {
462         static int prec;
463 
464         int i = *(loff_t *) v, j;
465         struct irqaction *action;
466         struct irq_desc *desc;
467         unsigned long flags;
468 
469         if (i > ACTUAL_NR_IRQS)
470                 return 0;
471 
472         if (i == ACTUAL_NR_IRQS)
473                 return arch_show_interrupts(p, prec);
474 
475         /* print header and calculate the width of the first column */
476         if (i == 0) {
477                 for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
478                         j *= 10;
479 
480                 seq_printf(p, "%*s", prec + 8, "");
481                 for_each_online_cpu(j)
482                         seq_printf(p, "CPU%-8d", j);
483                 seq_putc(p, '\n');
484         }
485 
486         rcu_read_lock();
487         desc = irq_to_desc(i);
488         if (!desc || irq_settings_is_hidden(desc))
489                 goto outsparse;
490 
491         if (!desc->action || irq_desc_is_chained(desc) || !desc->kstat_irqs)
492                 goto outsparse;
493 
494         seq_printf(p, "%*d: ", prec, i);
495         for_each_online_cpu(j)
496                 seq_printf(p, "%10u ", desc->kstat_irqs ? per_cpu(desc->kstat_irqs->cnt, j) : 0);
497 
498         raw_spin_lock_irqsave(&desc->lock, flags);
499         if (desc->irq_data.chip) {
500                 if (desc->irq_data.chip->irq_print_chip)
501                         desc->irq_data.chip->irq_print_chip(&desc->irq_data, p);
502                 else if (desc->irq_data.chip->name)
503                         seq_printf(p, " %8s", desc->irq_data.chip->name);
504                 else
505                         seq_printf(p, " %8s", "-");
506         } else {
507                 seq_printf(p, " %8s", "None");
508         }
509         if (desc->irq_data.domain)
510                 seq_printf(p, " %*lu", prec, desc->irq_data.hwirq);
511         else
512                 seq_printf(p, " %*s", prec, "");
513 #ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
514         seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
515 #endif
516         if (desc->name)
517                 seq_printf(p, "-%-8s", desc->name);
518 
519         action = desc->action;
520         if (action) {
521                 seq_printf(p, "  %s", action->name);
522                 while ((action = action->next) != NULL)
523                         seq_printf(p, ", %s", action->name);
524         }
525 
526         seq_putc(p, '\n');
527         raw_spin_unlock_irqrestore(&desc->lock, flags);
528 outsparse:
529         rcu_read_unlock();
530         return 0;
531 }
532 #endif
533 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php