Blame view
kernel/irq/proc.c
7.74 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 |
/* * linux/kernel/irq/proc.c * * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar * * This file contains the /proc/irq/ handling code. */ #include <linux/irq.h> |
5a0e3ad6a
|
10 |
#include <linux/gfp.h> |
1da177e4c
|
11 |
#include <linux/proc_fs.h> |
f18e439d1
|
12 |
#include <linux/seq_file.h> |
1da177e4c
|
13 |
#include <linux/interrupt.h> |
97a41e261
|
14 |
#include "internals.h" |
4a733ee12
|
15 |
static struct proc_dir_entry *root_irq_dir; |
1da177e4c
|
16 17 |
#ifdef CONFIG_SMP |
f18e439d1
|
18 |
static int irq_affinity_proc_show(struct seq_file *m, void *v) |
1da177e4c
|
19 |
{ |
08678b084
|
20 |
struct irq_desc *desc = irq_to_desc((long)m->private); |
7f7ace0cd
|
21 |
const struct cpumask *mask = desc->affinity; |
42ee2b741
|
22 23 24 |
#ifdef CONFIG_GENERIC_PENDING_IRQ if (desc->status & IRQ_MOVE_PENDING) |
7f7ace0cd
|
25 |
mask = desc->pending_mask; |
42ee2b741
|
26 |
#endif |
f18e439d1
|
27 28 29 30 |
seq_cpumask(m, mask); seq_putc(m, ' '); return 0; |
1da177e4c
|
31 |
} |
e7a297b0d
|
32 33 34 35 36 |
static int irq_affinity_hint_proc_show(struct seq_file *m, void *v) { struct irq_desc *desc = irq_to_desc((long)m->private); unsigned long flags; cpumask_var_t mask; |
4308ad801
|
37 |
if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) |
e7a297b0d
|
38 39 40 41 42 |
return -ENOMEM; raw_spin_lock_irqsave(&desc->lock, flags); if (desc->affinity_hint) cpumask_copy(mask, desc->affinity_hint); |
e7a297b0d
|
43 44 45 46 47 48 49 50 51 |
raw_spin_unlock_irqrestore(&desc->lock, flags); seq_cpumask(m, mask); seq_putc(m, ' '); free_cpumask_var(mask); return 0; } |
25d61578d
|
52 53 54 |
#ifndef is_affinity_mask_valid #define is_affinity_mask_valid(val) 1 #endif |
1da177e4c
|
55 |
int no_irq_affinity; |
f18e439d1
|
56 57 |
static ssize_t irq_affinity_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) |
1da177e4c
|
58 |
{ |
f18e439d1
|
59 |
unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data; |
0de26520c
|
60 |
cpumask_var_t new_value; |
f18e439d1
|
61 |
int err; |
1da177e4c
|
62 |
|
08678b084
|
63 |
if (!irq_to_desc(irq)->chip->set_affinity || no_irq_affinity || |
950f4427c
|
64 |
irq_balancing_disabled(irq)) |
1da177e4c
|
65 |
return -EIO; |
0de26520c
|
66 67 68 69 |
if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) return -ENOMEM; err = cpumask_parse_user(buffer, count, new_value); |
1da177e4c
|
70 |
if (err) |
0de26520c
|
71 |
goto free_cpumask; |
1da177e4c
|
72 |
|
6bdf197b0
|
73 |
if (!is_affinity_mask_valid(new_value)) { |
0de26520c
|
74 75 76 |
err = -EINVAL; goto free_cpumask; } |
25d61578d
|
77 |
|
1da177e4c
|
78 79 80 81 82 |
/* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. */ |
0de26520c
|
83 |
if (!cpumask_intersects(new_value, cpu_online_mask)) { |
eee45269b
|
84 85 |
/* Special case for empty set - allow the architecture code to set default SMP affinity. */ |
0de26520c
|
86 87 88 89 90 91 92 93 94 |
err = irq_select_affinity_usr(irq) ? -EINVAL : count; } else { irq_set_affinity(irq, new_value); err = count; } free_cpumask: free_cpumask_var(new_value); return err; |
1da177e4c
|
95 |
} |
f18e439d1
|
96 |
static int irq_affinity_proc_open(struct inode *inode, struct file *file) |
184047567
|
97 |
{ |
f18e439d1
|
98 |
return single_open(file, irq_affinity_proc_show, PDE(inode)->data); |
184047567
|
99 |
} |
e7a297b0d
|
100 101 102 103 |
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); } |
f18e439d1
|
104 105 106 107 108 109 110 |
static const struct file_operations irq_affinity_proc_fops = { .open = irq_affinity_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = irq_affinity_proc_write, }; |
e7a297b0d
|
111 112 113 114 115 116 |
static const struct file_operations irq_affinity_hint_proc_fops = { .open = irq_affinity_hint_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; |
f18e439d1
|
117 118 |
static int default_affinity_show(struct seq_file *m, void *v) { |
d036e67b4
|
119 |
seq_cpumask(m, irq_default_affinity); |
f18e439d1
|
120 121 122 123 124 125 126 |
seq_putc(m, ' '); return 0; } static ssize_t default_affinity_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
184047567
|
127 |
{ |
d036e67b4
|
128 |
cpumask_var_t new_value; |
f18e439d1
|
129 |
int err; |
184047567
|
130 |
|
d036e67b4
|
131 132 133 134 |
if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) return -ENOMEM; err = cpumask_parse_user(buffer, count, new_value); |
184047567
|
135 |
if (err) |
d036e67b4
|
136 |
goto out; |
184047567
|
137 |
|
d036e67b4
|
138 139 140 141 |
if (!is_affinity_mask_valid(new_value)) { err = -EINVAL; goto out; } |
184047567
|
142 143 144 145 146 147 |
/* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. */ |
d036e67b4
|
148 149 150 151 |
if (!cpumask_intersects(new_value, cpu_online_mask)) { err = -EINVAL; goto out; } |
184047567
|
152 |
|
d036e67b4
|
153 154 |
cpumask_copy(irq_default_affinity, new_value); err = count; |
184047567
|
155 |
|
d036e67b4
|
156 157 158 |
out: free_cpumask_var(new_value); return err; |
184047567
|
159 |
} |
f18e439d1
|
160 161 162 |
static int default_affinity_open(struct inode *inode, struct file *file) { |
34769945f
|
163 |
return single_open(file, default_affinity_show, PDE(inode)->data); |
f18e439d1
|
164 165 166 167 168 169 170 171 172 |
} static const struct file_operations default_affinity_proc_fops = { .open = default_affinity_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = default_affinity_write, }; |
92d6b71ab
|
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
static int irq_node_proc_show(struct seq_file *m, void *v) { struct irq_desc *desc = irq_to_desc((long) m->private); seq_printf(m, "%d ", desc->node); return 0; } static int irq_node_proc_open(struct inode *inode, struct file *file) { return single_open(file, irq_node_proc_show, PDE(inode)->data); } static const struct file_operations irq_node_proc_fops = { .open = irq_node_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; |
1da177e4c
|
194 |
#endif |
a1afb6371
|
195 |
static int irq_spurious_proc_show(struct seq_file *m, void *v) |
96d97cf03
|
196 |
{ |
a1afb6371
|
197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
struct irq_desc *desc = irq_to_desc((long) m->private); seq_printf(m, "count %u " "unhandled %u " "last_unhandled %u ms ", desc->irq_count, desc->irqs_unhandled, jiffies_to_msecs(desc->last_unhandled)); return 0; } static int irq_spurious_proc_open(struct inode *inode, struct file *file) { return single_open(file, irq_spurious_proc_show, NULL); |
96d97cf03
|
211 |
} |
a1afb6371
|
212 213 214 215 216 217 |
static const struct file_operations irq_spurious_proc_fops = { .open = irq_spurious_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; |
1da177e4c
|
218 219 220 221 |
#define MAX_NAMELEN 128 static int name_unique(unsigned int irq, struct irqaction *new_action) { |
08678b084
|
222 |
struct irq_desc *desc = irq_to_desc(irq); |
1da177e4c
|
223 |
struct irqaction *action; |
d2d9433a4
|
224 225 |
unsigned long flags; int ret = 1; |
1da177e4c
|
226 |
|
239007b84
|
227 |
raw_spin_lock_irqsave(&desc->lock, flags); |
d2d9433a4
|
228 |
for (action = desc->action ; action; action = action->next) { |
1da177e4c
|
229 |
if ((action != new_action) && action->name && |
d2d9433a4
|
230 231 232 233 234 |
!strcmp(new_action->name, action->name)) { ret = 0; break; } } |
239007b84
|
235 |
raw_spin_unlock_irqrestore(&desc->lock, flags); |
d2d9433a4
|
236 |
return ret; |
1da177e4c
|
237 238 239 240 241 |
} void register_handler_proc(unsigned int irq, struct irqaction *action) { char name [MAX_NAMELEN]; |
08678b084
|
242 |
struct irq_desc *desc = irq_to_desc(irq); |
1da177e4c
|
243 |
|
08678b084
|
244 |
if (!desc->dir || action->dir || !action->name || |
1da177e4c
|
245 246 247 248 249 250 251 |
!name_unique(irq, action)) return; memset(name, 0, MAX_NAMELEN); snprintf(name, MAX_NAMELEN, "%s", action->name); /* create /proc/irq/1234/handler/ */ |
08678b084
|
252 |
action->dir = proc_mkdir(name, desc->dir); |
1da177e4c
|
253 254 255 256 257 |
} #undef MAX_NAMELEN #define MAX_NAMELEN 10 |
2c6927a38
|
258 |
void register_irq_proc(unsigned int irq, struct irq_desc *desc) |
1da177e4c
|
259 260 |
{ char name [MAX_NAMELEN]; |
08678b084
|
261 |
if (!root_irq_dir || (desc->chip == &no_irq_chip) || desc->dir) |
1da177e4c
|
262 263 264 265 266 267 |
return; memset(name, 0, MAX_NAMELEN); sprintf(name, "%d", irq); /* create /proc/irq/1234 */ |
08678b084
|
268 |
desc->dir = proc_mkdir(name, root_irq_dir); |
c82a43d40
|
269 270 |
if (!desc->dir) return; |
1da177e4c
|
271 272 |
#ifdef CONFIG_SMP |
f18e439d1
|
273 |
/* create /proc/irq/<irq>/smp_affinity */ |
08678b084
|
274 |
proc_create_data("smp_affinity", 0600, desc->dir, |
f18e439d1
|
275 |
&irq_affinity_proc_fops, (void *)(long)irq); |
92d6b71ab
|
276 |
|
e7a297b0d
|
277 278 279 |
/* create /proc/irq/<irq>/affinity_hint */ proc_create_data("affinity_hint", 0400, desc->dir, &irq_affinity_hint_proc_fops, (void *)(long)irq); |
92d6b71ab
|
280 281 |
proc_create_data("node", 0444, desc->dir, &irq_node_proc_fops, (void *)(long)irq); |
1da177e4c
|
282 |
#endif |
96d97cf03
|
283 |
|
a1afb6371
|
284 285 |
proc_create_data("spurious", 0444, desc->dir, &irq_spurious_proc_fops, (void *)(long)irq); |
1da177e4c
|
286 287 288 289 290 291 |
} #undef MAX_NAMELEN void unregister_handler_proc(unsigned int irq, struct irqaction *action) { |
08678b084
|
292 293 |
if (action->dir) { struct irq_desc *desc = irq_to_desc(irq); |
d3c60047b
|
294 |
|
08678b084
|
295 296 |
remove_proc_entry(action->dir->name, desc->dir); } |
1da177e4c
|
297 |
} |
3786fc710
|
298 |
static void register_default_affinity_proc(void) |
184047567
|
299 300 |
{ #ifdef CONFIG_SMP |
f18e439d1
|
301 302 |
proc_create("irq/default_smp_affinity", 0600, NULL, &default_affinity_proc_fops); |
184047567
|
303 304 |
#endif } |
1da177e4c
|
305 306 |
void init_irq_proc(void) { |
2c6927a38
|
307 308 |
unsigned int irq; struct irq_desc *desc; |
1da177e4c
|
309 310 311 312 313 |
/* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); if (!root_irq_dir) return; |
184047567
|
314 |
register_default_affinity_proc(); |
1da177e4c
|
315 316 317 |
/* * Create entries for all existing IRQs. */ |
0b8f1efad
|
318 319 320 |
for_each_irq_desc(irq, desc) { if (!desc) continue; |
2c6927a38
|
321 |
register_irq_proc(irq, desc); |
0b8f1efad
|
322 |
} |
1da177e4c
|
323 |
} |