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