linux/kernel/irq/proc.c
<<
>>
Prefs
   1/*
   2 * linux/kernel/irq/proc.c
   3 *
   4 * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
   5 *
   6 * This file contains the /proc/irq/ handling code.
   7 */
   8
   9#include <linux/irq.h>
  10#include <linux/gfp.h>
  11#include <linux/proc_fs.h>
  12#include <linux/seq_file.h>
  13#include <linux/interrupt.h>
  14#include <linux/kernel_stat.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 */
  35static struct proc_dir_entry *root_irq_dir;
  36
  37#ifdef CONFIG_SMP
  38
  39static int show_irq_affinity(int type, struct seq_file *m, void *v)
  40{
  41        struct irq_desc *desc = irq_to_desc((long)m->private);
  42        const struct cpumask *mask = desc->irq_data.affinity;
  43
  44#ifdef CONFIG_GENERIC_PENDING_IRQ
  45        if (irqd_is_setaffinity_pending(&desc->irq_data))
  46                mask = desc->pending_mask;
  47#endif
  48        if (type)
  49                seq_printf(m, "%*pbl\n", cpumask_pr_args(mask));
  50        else
  51                seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
  52        return 0;
  53}
  54
  55static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)
  56{
  57        struct irq_desc *desc = irq_to_desc((long)m->private);
  58        unsigned long flags;
  59        cpumask_var_t mask;
  60
  61        if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
  62                return -ENOMEM;
  63
  64        raw_spin_lock_irqsave(&desc->lock, flags);
  65        if (desc->affinity_hint)
  66                cpumask_copy(mask, desc->affinity_hint);
  67        raw_spin_unlock_irqrestore(&desc->lock, flags);
  68
  69        seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
  70        free_cpumask_var(mask);
  71
  72        return 0;
  73}
  74
  75#ifndef is_affinity_mask_valid
  76#define is_affinity_mask_valid(val) 1
  77#endif
  78
  79int no_irq_affinity;
  80static int irq_affinity_proc_show(struct seq_file *m, void *v)
  81{
  82        return show_irq_affinity(0, m, v);
  83}
  84
  85static int irq_affinity_list_proc_show(struct seq_file *m, void *v)
  86{
  87        return show_irq_affinity(1, m, v);
  88}
  89
  90
  91static ssize_t write_irq_affinity(int type, struct file *file,
  92                const char __user *buffer, size_t count, loff_t *pos)
  93{
  94        unsigned int irq = (int)(long)PDE_DATA(file_inode(file));
  95        cpumask_var_t new_value;
  96        int err;
  97
  98        if (!irq_can_set_affinity(irq) || no_irq_affinity)
  99                return -EIO;
 100
 101        if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
 102                return -ENOMEM;
 103
 104        if (type)
 105                err = cpumask_parselist_user(buffer, count, new_value);
 106        else
 107                err = cpumask_parse_user(buffer, count, new_value);
 108        if (err)
 109                goto free_cpumask;
 110
 111        if (!is_affinity_mask_valid(new_value)) {
 112                err = -EINVAL;
 113                goto free_cpumask;
 114        }
 115
 116        /*
 117         * Do not allow disabling IRQs completely - it's a too easy
 118         * way to make the system unusable accidentally :-) At least
 119         * one online CPU still has to be targeted.
 120         */
 121        if (!cpumask_intersects(new_value, cpu_online_mask)) {
 122                /* Special case for empty set - allow the architecture
 123                   code to set default SMP affinity. */
 124                err = irq_select_affinity_usr(irq, new_value) ? -EINVAL : count;
 125        } else {
 126                irq_set_affinity(irq, new_value);
 127                err = count;
 128        }
 129
 130free_cpumask:
 131        free_cpumask_var(new_value);
 132        return err;
 133}
 134
 135static ssize_t irq_affinity_proc_write(struct file *file,
 136                const char __user *buffer, size_t count, loff_t *pos)
 137{
 138        return write_irq_affinity(0, file, buffer, count, pos);
 139}
 140
 141static ssize_t irq_affinity_list_proc_write(struct file *file,
 142                const char __user *buffer, size_t count, loff_t *pos)
 143{
 144        return write_irq_affinity(1, file, buffer, count, pos);
 145}
 146
 147static int irq_affinity_proc_open(struct inode *inode, struct file *file)
 148{
 149        return single_open(file, irq_affinity_proc_show, PDE_DATA(inode));
 150}
 151
 152static int irq_affinity_list_proc_open(struct inode *inode, struct file *file)
 153{
 154        return single_open(file, irq_affinity_list_proc_show, PDE_DATA(inode));
 155}
 156
 157static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file)
 158{
 159        return single_open(file, irq_affinity_hint_proc_show, PDE_DATA(inode));
 160}
 161
 162static const struct file_operations irq_affinity_proc_fops = {
 163        .open           = irq_affinity_proc_open,
 164        .read           = seq_read,
 165        .llseek         = seq_lseek,
 166        .release        = single_release,
 167        .write          = irq_affinity_proc_write,
 168};
 169
 170static const struct file_operations irq_affinity_hint_proc_fops = {
 171        .open           = irq_affinity_hint_proc_open,
 172        .read           = seq_read,
 173        .llseek         = seq_lseek,
 174        .release        = single_release,
 175};
 176
 177static const struct file_operations irq_affinity_list_proc_fops = {
 178        .open           = irq_affinity_list_proc_open,
 179        .read           = seq_read,
 180        .llseek         = seq_lseek,
 181        .release        = single_release,
 182        .write          = irq_affinity_list_proc_write,
 183};
 184
 185static int default_affinity_show(struct seq_file *m, void *v)
 186{
 187        seq_printf(m, "%*pb\n", cpumask_pr_args(irq_default_affinity));
 188        return 0;
 189}
 190
 191static ssize_t default_affinity_write(struct file *file,
 192                const char __user *buffer, size_t count, loff_t *ppos)
 193{
 194        cpumask_var_t new_value;
 195        int err;
 196
 197        if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
 198                return -ENOMEM;
 199
 200        err = cpumask_parse_user(buffer, count, new_value);
 201        if (err)
 202                goto out;
 203
 204        if (!is_affinity_mask_valid(new_value)) {
 205                err = -EINVAL;
 206                goto out;
 207        }
 208
 209        /*
 210         * Do not allow disabling IRQs completely - it's a too easy
 211         * way to make the system unusable accidentally :-) At least
 212         * one online CPU still has to be targeted.
 213         */
 214        if (!cpumask_intersects(new_value, cpu_online_mask)) {
 215                err = -EINVAL;
 216                goto out;
 217        }
 218
 219        cpumask_copy(irq_default_affinity, new_value);
 220        err = count;
 221
 222out:
 223        free_cpumask_var(new_value);
 224        return err;
 225}
 226
 227static int default_affinity_open(struct inode *inode, struct file *file)
 228{
 229        return single_open(file, default_affinity_show, PDE_DATA(inode));
 230}
 231
 232static const struct file_operations default_affinity_proc_fops = {
 233        .open           = default_affinity_open,
 234        .read           = seq_read,
 235        .llseek         = seq_lseek,
 236        .release        = single_release,
 237        .write          = default_affinity_write,
 238};
 239
 240static int irq_node_proc_show(struct seq_file *m, void *v)
 241{
 242        struct irq_desc *desc = irq_to_desc((long) m->private);
 243
 244        seq_printf(m, "%d\n", desc->irq_data.node);
 245        return 0;
 246}
 247
 248static int irq_node_proc_open(struct inode *inode, struct file *file)
 249{
 250        return single_open(file, irq_node_proc_show, PDE_DATA(inode));
 251}
 252
 253static const struct file_operations irq_node_proc_fops = {
 254        .open           = irq_node_proc_open,
 255        .read           = seq_read,
 256        .llseek         = seq_lseek,
 257        .release        = single_release,
 258};
 259#endif
 260
 261static int irq_spurious_proc_show(struct seq_file *m, void *v)
 262{
 263        struct irq_desc *desc = irq_to_desc((long) m->private);
 264
 265        seq_printf(m, "count %u\n" "unhandled %u\n" "last_unhandled %u ms\n",
 266                   desc->irq_count, desc->irqs_unhandled,
 267                   jiffies_to_msecs(desc->last_unhandled));
 268        return 0;
 269}
 270
 271static int irq_spurious_proc_open(struct inode *inode, struct file *file)
 272{
 273        return single_open(file, irq_spurious_proc_show, PDE_DATA(inode));
 274}
 275
 276static const struct file_operations irq_spurious_proc_fops = {
 277        .open           = irq_spurious_proc_open,
 278        .read           = seq_read,
 279        .llseek         = seq_lseek,
 280        .release        = single_release,
 281};
 282
 283#define MAX_NAMELEN 128
 284
 285static int name_unique(unsigned int irq, struct irqaction *new_action)
 286{
 287        struct irq_desc *desc = irq_to_desc(irq);
 288        struct irqaction *action;
 289        unsigned long flags;
 290        int ret = 1;
 291
 292        raw_spin_lock_irqsave(&desc->lock, flags);
 293        for (action = desc->action ; action; action = action->next) {
 294                if ((action != new_action) && action->name &&
 295                                !strcmp(new_action->name, action->name)) {
 296                        ret = 0;
 297                        break;
 298                }
 299        }
 300        raw_spin_unlock_irqrestore(&desc->lock, flags);
 301        return ret;
 302}
 303
 304void register_handler_proc(unsigned int irq, struct irqaction *action)
 305{
 306        char name [MAX_NAMELEN];
 307        struct irq_desc *desc = irq_to_desc(irq);
 308
 309        if (!desc->dir || action->dir || !action->name ||
 310                                        !name_unique(irq, action))
 311                return;
 312
 313        memset(name, 0, MAX_NAMELEN);
 314        snprintf(name, MAX_NAMELEN, "%s", action->name);
 315
 316        /* create /proc/irq/1234/handler/ */
 317        action->dir = proc_mkdir(name, desc->dir);
 318}
 319
 320#undef MAX_NAMELEN
 321
 322#define MAX_NAMELEN 10
 323
 324void register_irq_proc(unsigned int irq, struct irq_desc *desc)
 325{
 326        char name [MAX_NAMELEN];
 327
 328        if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip) || desc->dir)
 329                return;
 330
 331        memset(name, 0, MAX_NAMELEN);
 332        sprintf(name, "%d", irq);
 333
 334        /* create /proc/irq/1234 */
 335        desc->dir = proc_mkdir(name, root_irq_dir);
 336        if (!desc->dir)
 337                return;
 338
 339#ifdef CONFIG_SMP
 340        /* create /proc/irq/<irq>/smp_affinity */
 341        proc_create_data("smp_affinity", 0644, desc->dir,
 342                         &irq_affinity_proc_fops, (void *)(long)irq);
 343
 344        /* create /proc/irq/<irq>/affinity_hint */
 345        proc_create_data("affinity_hint", 0444, desc->dir,
 346                         &irq_affinity_hint_proc_fops, (void *)(long)irq);
 347
 348        /* create /proc/irq/<irq>/smp_affinity_list */
 349        proc_create_data("smp_affinity_list", 0644, desc->dir,
 350                         &irq_affinity_list_proc_fops, (void *)(long)irq);
 351
 352        proc_create_data("node", 0444, desc->dir,
 353                         &irq_node_proc_fops, (void *)(long)irq);
 354#endif
 355
 356        proc_create_data("spurious", 0444, desc->dir,
 357                         &irq_spurious_proc_fops, (void *)(long)irq);
 358}
 359
 360void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)
 361{
 362        char name [MAX_NAMELEN];
 363
 364        if (!root_irq_dir || !desc->dir)
 365                return;
 366#ifdef CONFIG_SMP
 367        remove_proc_entry("smp_affinity", desc->dir);
 368        remove_proc_entry("affinity_hint", desc->dir);
 369        remove_proc_entry("smp_affinity_list", desc->dir);
 370        remove_proc_entry("node", desc->dir);
 371#endif
 372        remove_proc_entry("spurious", desc->dir);
 373
 374        memset(name, 0, MAX_NAMELEN);
 375        sprintf(name, "%u", irq);
 376        remove_proc_entry(name, root_irq_dir);
 377}
 378
 379#undef MAX_NAMELEN
 380
 381void unregister_handler_proc(unsigned int irq, struct irqaction *action)
 382{
 383        proc_remove(action->dir);
 384}
 385
 386static void register_default_affinity_proc(void)
 387{
 388#ifdef CONFIG_SMP
 389        proc_create("irq/default_smp_affinity", 0644, NULL,
 390                    &default_affinity_proc_fops);
 391#endif
 392}
 393
 394void init_irq_proc(void)
 395{
 396        unsigned int irq;
 397        struct irq_desc *desc;
 398
 399        /* create /proc/irq */
 400        root_irq_dir = proc_mkdir("irq", NULL);
 401        if (!root_irq_dir)
 402                return;
 403
 404        register_default_affinity_proc();
 405
 406        /*
 407         * Create entries for all existing IRQs.
 408         */
 409        for_each_irq_desc(irq, desc) {
 410                if (!desc)
 411                        continue;
 412
 413                register_irq_proc(irq, desc);
 414        }
 415}
 416
 417#ifdef CONFIG_GENERIC_IRQ_SHOW
 418
 419int __weak arch_show_interrupts(struct seq_file *p, int prec)
 420{
 421        return 0;
 422}
 423
 424#ifndef ACTUAL_NR_IRQS
 425# define ACTUAL_NR_IRQS nr_irqs
 426#endif
 427
 428int show_interrupts(struct seq_file *p, void *v)
 429{
 430        static int prec;
 431
 432        unsigned long flags, any_count = 0;
 433        int i = *(loff_t *) v, j;
 434        struct irqaction *action;
 435        struct irq_desc *desc;
 436
 437        if (i > ACTUAL_NR_IRQS)
 438                return 0;
 439
 440        if (i == ACTUAL_NR_IRQS)
 441                return arch_show_interrupts(p, prec);
 442
 443        /* print header and calculate the width of the first column */
 444        if (i == 0) {
 445                for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
 446                        j *= 10;
 447
 448                seq_printf(p, "%*s", prec + 8, "");
 449                for_each_online_cpu(j)
 450                        seq_printf(p, "CPU%-8d", j);
 451                seq_putc(p, '\n');
 452        }
 453
 454        irq_lock_sparse();
 455        desc = irq_to_desc(i);
 456        if (!desc)
 457                goto outsparse;
 458
 459        raw_spin_lock_irqsave(&desc->lock, flags);
 460        for_each_online_cpu(j)
 461                any_count |= kstat_irqs_cpu(i, j);
 462        action = desc->action;
 463        if (!action && !any_count)
 464                goto out;
 465
 466        seq_printf(p, "%*d: ", prec, i);
 467        for_each_online_cpu(j)
 468                seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 469
 470        if (desc->irq_data.chip) {
 471                if (desc->irq_data.chip->irq_print_chip)
 472                        desc->irq_data.chip->irq_print_chip(&desc->irq_data, p);
 473                else if (desc->irq_data.chip->name)
 474                        seq_printf(p, " %8s", desc->irq_data.chip->name);
 475                else
 476                        seq_printf(p, " %8s", "-");
 477        } else {
 478                seq_printf(p, " %8s", "None");
 479        }
 480        if (desc->irq_data.domain)
 481                seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq);
 482#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
 483        seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
 484#endif
 485        if (desc->name)
 486                seq_printf(p, "-%-8s", desc->name);
 487
 488        if (action) {
 489                seq_printf(p, "  %s", action->name);
 490                while ((action = action->next) != NULL)
 491                        seq_printf(p, ", %s", action->name);
 492        }
 493
 494        seq_putc(p, '\n');
 495out:
 496        raw_spin_unlock_irqrestore(&desc->lock, flags);
 497outsparse:
 498        irq_unlock_sparse();
 499        return 0;
 500}
 501#endif
 502