diff options
Diffstat (limited to 'kernel/irq/proc.c')
| -rw-r--r-- | kernel/irq/proc.c | 169 | 
1 files changed, 147 insertions, 22 deletions
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 01b1d3a8898..ac1ba2f1103 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -11,6 +11,7 @@  #include <linux/proc_fs.h>  #include <linux/seq_file.h>  #include <linux/interrupt.h> +#include <linux/kernel_stat.h>  #include "internals.h" @@ -18,16 +19,19 @@ static struct proc_dir_entry *root_irq_dir;  #ifdef CONFIG_SMP -static int irq_affinity_proc_show(struct seq_file *m, void *v) +static int show_irq_affinity(int type, struct seq_file *m, void *v)  {  	struct irq_desc *desc = irq_to_desc((long)m->private);  	const struct cpumask *mask = desc->irq_data.affinity;  #ifdef CONFIG_GENERIC_PENDING_IRQ -	if (desc->status & IRQ_MOVE_PENDING) +	if (irqd_is_setaffinity_pending(&desc->irq_data))  		mask = desc->pending_mask;  #endif -	seq_cpumask(m, mask); +	if (type) +		seq_cpumask_list(m, mask); +	else +		seq_cpumask(m, mask);  	seq_putc(m, '\n');  	return 0;  } @@ -58,21 +62,34 @@ static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)  #endif  int no_irq_affinity; -static ssize_t irq_affinity_proc_write(struct file *file, +static int irq_affinity_proc_show(struct seq_file *m, void *v) +{ +	return show_irq_affinity(0, m, v); +} + +static int irq_affinity_list_proc_show(struct seq_file *m, void *v) +{ +	return show_irq_affinity(1, m, v); +} + + +static ssize_t write_irq_affinity(int type, struct file *file,  		const char __user *buffer, size_t count, loff_t *pos)  { -	unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data; +	unsigned int irq = (int)(long)PDE_DATA(file_inode(file));  	cpumask_var_t new_value;  	int err; -	if (!irq_to_desc(irq)->irq_data.chip->irq_set_affinity || no_irq_affinity || -	    irq_balancing_disabled(irq)) +	if (!irq_can_set_affinity(irq) || no_irq_affinity)  		return -EIO;  	if (!alloc_cpumask_var(&new_value, GFP_KERNEL))  		return -ENOMEM; -	err = cpumask_parse_user(buffer, count, new_value); +	if (type) +		err = cpumask_parselist_user(buffer, count, new_value); +	else +		err = cpumask_parse_user(buffer, count, new_value);  	if (err)  		goto free_cpumask; @@ -89,7 +106,7 @@ static ssize_t irq_affinity_proc_write(struct file *file,  	if (!cpumask_intersects(new_value, cpu_online_mask)) {  		/* Special case for empty set - allow the architecture  		   code to set default SMP affinity. */ -		err = irq_select_affinity_usr(irq) ? -EINVAL : count; +		err = irq_select_affinity_usr(irq, new_value) ? -EINVAL : count;  	} else {  		irq_set_affinity(irq, new_value);  		err = count; @@ -100,14 +117,31 @@ free_cpumask:  	return err;  } +static ssize_t irq_affinity_proc_write(struct file *file, +		const char __user *buffer, size_t count, loff_t *pos) +{ +	return write_irq_affinity(0, file, buffer, count, pos); +} + +static ssize_t irq_affinity_list_proc_write(struct file *file, +		const char __user *buffer, size_t count, loff_t *pos) +{ +	return write_irq_affinity(1, file, buffer, count, pos); +} +  static int irq_affinity_proc_open(struct inode *inode, struct file *file)  { -	return single_open(file, irq_affinity_proc_show, PDE(inode)->data); +	return single_open(file, irq_affinity_proc_show, PDE_DATA(inode)); +} + +static int irq_affinity_list_proc_open(struct inode *inode, struct file *file) +{ +	return single_open(file, irq_affinity_list_proc_show, PDE_DATA(inode));  }  static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file)  { -	return single_open(file, irq_affinity_hint_proc_show, PDE(inode)->data); +	return single_open(file, irq_affinity_hint_proc_show, PDE_DATA(inode));  }  static const struct file_operations irq_affinity_proc_fops = { @@ -125,6 +159,14 @@ static const struct file_operations irq_affinity_hint_proc_fops = {  	.release	= single_release,  }; +static const struct file_operations irq_affinity_list_proc_fops = { +	.open		= irq_affinity_list_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +	.write		= irq_affinity_list_proc_write, +}; +  static int default_affinity_show(struct seq_file *m, void *v)  {  	seq_cpumask(m, irq_default_affinity); @@ -170,7 +212,7 @@ out:  static int default_affinity_open(struct inode *inode, struct file *file)  { -	return single_open(file, default_affinity_show, PDE(inode)->data); +	return single_open(file, default_affinity_show, PDE_DATA(inode));  }  static const struct file_operations default_affinity_proc_fops = { @@ -191,7 +233,7 @@ static int irq_node_proc_show(struct seq_file *m, void *v)  static int irq_node_proc_open(struct inode *inode, struct file *file)  { -	return single_open(file, irq_node_proc_show, PDE(inode)->data); +	return single_open(file, irq_node_proc_show, PDE_DATA(inode));  }  static const struct file_operations irq_node_proc_fops = { @@ -214,7 +256,7 @@ static int irq_spurious_proc_show(struct seq_file *m, void *v)  static int irq_spurious_proc_open(struct inode *inode, struct file *file)  { -	return single_open(file, irq_spurious_proc_show, NULL); +	return single_open(file, irq_spurious_proc_show, PDE_DATA(inode));  }  static const struct file_operations irq_spurious_proc_fops = { @@ -282,13 +324,17 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)  #ifdef CONFIG_SMP  	/* create /proc/irq/<irq>/smp_affinity */ -	proc_create_data("smp_affinity", 0600, desc->dir, +	proc_create_data("smp_affinity", 0644, desc->dir,  			 &irq_affinity_proc_fops, (void *)(long)irq);  	/* create /proc/irq/<irq>/affinity_hint */ -	proc_create_data("affinity_hint", 0400, desc->dir, +	proc_create_data("affinity_hint", 0444, desc->dir,  			 &irq_affinity_hint_proc_fops, (void *)(long)irq); +	/* create /proc/irq/<irq>/smp_affinity_list */ +	proc_create_data("smp_affinity_list", 0644, desc->dir, +			 &irq_affinity_list_proc_fops, (void *)(long)irq); +  	proc_create_data("node", 0444, desc->dir,  			 &irq_node_proc_fops, (void *)(long)irq);  #endif @@ -306,6 +352,7 @@ void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)  #ifdef CONFIG_SMP  	remove_proc_entry("smp_affinity", desc->dir);  	remove_proc_entry("affinity_hint", desc->dir); +	remove_proc_entry("smp_affinity_list", desc->dir);  	remove_proc_entry("node", desc->dir);  #endif  	remove_proc_entry("spurious", desc->dir); @@ -319,17 +366,13 @@ void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)  void unregister_handler_proc(unsigned int irq, struct irqaction *action)  { -	if (action->dir) { -		struct irq_desc *desc = irq_to_desc(irq); - -		remove_proc_entry(action->dir->name, desc->dir); -	} +	proc_remove(action->dir);  }  static void register_default_affinity_proc(void)  {  #ifdef CONFIG_SMP -	proc_create("irq/default_smp_affinity", 0600, NULL, +	proc_create("irq/default_smp_affinity", 0644, NULL,  		    &default_affinity_proc_fops);  #endif  } @@ -357,3 +400,85 @@ void init_irq_proc(void)  	}  } +#ifdef CONFIG_GENERIC_IRQ_SHOW + +int __weak arch_show_interrupts(struct seq_file *p, int prec) +{ +	return 0; +} + +#ifndef ACTUAL_NR_IRQS +# define ACTUAL_NR_IRQS nr_irqs +#endif + +int show_interrupts(struct seq_file *p, void *v) +{ +	static int prec; + +	unsigned long flags, any_count = 0; +	int i = *(loff_t *) v, j; +	struct irqaction *action; +	struct irq_desc *desc; + +	if (i > ACTUAL_NR_IRQS) +		return 0; + +	if (i == ACTUAL_NR_IRQS) +		return arch_show_interrupts(p, prec); + +	/* print header and calculate the width of the first column */ +	if (i == 0) { +		for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec) +			j *= 10; + +		seq_printf(p, "%*s", prec + 8, ""); +		for_each_online_cpu(j) +			seq_printf(p, "CPU%-8d", j); +		seq_putc(p, '\n'); +	} + +	desc = irq_to_desc(i); +	if (!desc) +		return 0; + +	raw_spin_lock_irqsave(&desc->lock, flags); +	for_each_online_cpu(j) +		any_count |= kstat_irqs_cpu(i, j); +	action = desc->action; +	if (!action && !any_count) +		goto out; + +	seq_printf(p, "%*d: ", prec, i); +	for_each_online_cpu(j) +		seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); + +	if (desc->irq_data.chip) { +		if (desc->irq_data.chip->irq_print_chip) +			desc->irq_data.chip->irq_print_chip(&desc->irq_data, p); +		else if (desc->irq_data.chip->name) +			seq_printf(p, " %8s", desc->irq_data.chip->name); +		else +			seq_printf(p, " %8s", "-"); +	} else { +		seq_printf(p, " %8s", "None"); +	} +	if (desc->irq_data.domain) +		seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq); +#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL +	seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge"); +#endif +	if (desc->name) +		seq_printf(p, "-%-8s", desc->name); + +	if (action) { +		seq_printf(p, "  %s", action->name); +		while ((action = action->next) != NULL) +			seq_printf(p, ", %s", action->name); +	} + +	seq_putc(p, '\n'); +out: +	raw_spin_unlock_irqrestore(&desc->lock, flags); +	return 0; +} +#endif  | 
