aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/sysrq.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-10-05 09:55:46 -0400
committerDavid Howells <dhowells@warthog.cambridge.redhat.com>2006-10-05 10:10:12 -0400
commit7d12e780e003f93433d49ce78cfedf4b4c52adc5 (patch)
tree6748550400445c11a306b132009f3001e3525df8 /drivers/char/sysrq.c
parentda482792a6d1a3fbaaa25fae867b343fb4db3246 (diff)
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
Diffstat (limited to 'drivers/char/sysrq.c')
-rw-r--r--drivers/char/sysrq.c62
1 files changed, 24 insertions, 38 deletions
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 6b4d4d1e343d..4c0e08685705 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -35,14 +35,14 @@
35#include <linux/vt_kern.h> 35#include <linux/vt_kern.h>
36#include <linux/workqueue.h> 36#include <linux/workqueue.h>
37#include <linux/kexec.h> 37#include <linux/kexec.h>
38#include <linux/irq.h>
38 39
39#include <asm/ptrace.h> 40#include <asm/ptrace.h>
40 41
41/* Whether we react on sysrq keys or just ignore them */ 42/* Whether we react on sysrq keys or just ignore them */
42int sysrq_enabled = 1; 43int sysrq_enabled = 1;
43 44
44static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs, 45static void sysrq_handle_loglevel(int key, struct tty_struct *tty)
45 struct tty_struct *tty)
46{ 46{
47 int i; 47 int i;
48 i = key - '0'; 48 i = key - '0';
@@ -58,8 +58,7 @@ static struct sysrq_key_op sysrq_loglevel_op = {
58}; 58};
59 59
60#ifdef CONFIG_VT 60#ifdef CONFIG_VT
61static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs, 61static void sysrq_handle_SAK(int key, struct tty_struct *tty)
62 struct tty_struct *tty)
63{ 62{
64 if (tty) 63 if (tty)
65 do_SAK(tty); 64 do_SAK(tty);
@@ -76,8 +75,7 @@ static struct sysrq_key_op sysrq_SAK_op = {
76#endif 75#endif
77 76
78#ifdef CONFIG_VT 77#ifdef CONFIG_VT
79static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs, 78static void sysrq_handle_unraw(int key, struct tty_struct *tty)
80 struct tty_struct *tty)
81{ 79{
82 struct kbd_struct *kbd = &kbd_table[fg_console]; 80 struct kbd_struct *kbd = &kbd_table[fg_console];
83 81
@@ -95,10 +93,9 @@ static struct sysrq_key_op sysrq_unraw_op = {
95#endif /* CONFIG_VT */ 93#endif /* CONFIG_VT */
96 94
97#ifdef CONFIG_KEXEC 95#ifdef CONFIG_KEXEC
98static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, 96static void sysrq_handle_crashdump(int key, struct tty_struct *tty)
99 struct tty_struct *tty)
100{ 97{
101 crash_kexec(pt_regs); 98 crash_kexec(get_irq_regs());
102} 99}
103static struct sysrq_key_op sysrq_crashdump_op = { 100static struct sysrq_key_op sysrq_crashdump_op = {
104 .handler = sysrq_handle_crashdump, 101 .handler = sysrq_handle_crashdump,
@@ -110,8 +107,7 @@ static struct sysrq_key_op sysrq_crashdump_op = {
110#define sysrq_crashdump_op (*(struct sysrq_key_op *)0) 107#define sysrq_crashdump_op (*(struct sysrq_key_op *)0)
111#endif 108#endif
112 109
113static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, 110static void sysrq_handle_reboot(int key, struct tty_struct *tty)
114 struct tty_struct *tty)
115{ 111{
116 lockdep_off(); 112 lockdep_off();
117 local_irq_enable(); 113 local_irq_enable();
@@ -124,8 +120,7 @@ static struct sysrq_key_op sysrq_reboot_op = {
124 .enable_mask = SYSRQ_ENABLE_BOOT, 120 .enable_mask = SYSRQ_ENABLE_BOOT,
125}; 121};
126 122
127static void sysrq_handle_sync(int key, struct pt_regs *pt_regs, 123static void sysrq_handle_sync(int key, struct tty_struct *tty)
128 struct tty_struct *tty)
129{ 124{
130 emergency_sync(); 125 emergency_sync();
131} 126}
@@ -136,8 +131,7 @@ static struct sysrq_key_op sysrq_sync_op = {
136 .enable_mask = SYSRQ_ENABLE_SYNC, 131 .enable_mask = SYSRQ_ENABLE_SYNC,
137}; 132};
138 133
139static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, 134static void sysrq_handle_mountro(int key, struct tty_struct *tty)
140 struct tty_struct *tty)
141{ 135{
142 emergency_remount(); 136 emergency_remount();
143} 137}
@@ -149,8 +143,7 @@ static struct sysrq_key_op sysrq_mountro_op = {
149}; 143};
150 144
151#ifdef CONFIG_LOCKDEP 145#ifdef CONFIG_LOCKDEP
152static void sysrq_handle_showlocks(int key, struct pt_regs *pt_regs, 146static void sysrq_handle_showlocks(int key, struct tty_struct *tty)
153 struct tty_struct *tty)
154{ 147{
155 debug_show_all_locks(); 148 debug_show_all_locks();
156} 149}
@@ -164,11 +157,11 @@ static struct sysrq_key_op sysrq_showlocks_op = {
164#define sysrq_showlocks_op (*(struct sysrq_key_op *)0) 157#define sysrq_showlocks_op (*(struct sysrq_key_op *)0)
165#endif 158#endif
166 159
167static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs, 160static void sysrq_handle_showregs(int key, struct tty_struct *tty)
168 struct tty_struct *tty)
169{ 161{
170 if (pt_regs) 162 struct pt_regs *regs = get_irq_regs();
171 show_regs(pt_regs); 163 if (regs)
164 show_regs(regs);
172} 165}
173static struct sysrq_key_op sysrq_showregs_op = { 166static struct sysrq_key_op sysrq_showregs_op = {
174 .handler = sysrq_handle_showregs, 167 .handler = sysrq_handle_showregs,
@@ -177,8 +170,7 @@ static struct sysrq_key_op sysrq_showregs_op = {
177 .enable_mask = SYSRQ_ENABLE_DUMP, 170 .enable_mask = SYSRQ_ENABLE_DUMP,
178}; 171};
179 172
180static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs, 173static void sysrq_handle_showstate(int key, struct tty_struct *tty)
181 struct tty_struct *tty)
182{ 174{
183 show_state(); 175 show_state();
184} 176}
@@ -189,8 +181,7 @@ static struct sysrq_key_op sysrq_showstate_op = {
189 .enable_mask = SYSRQ_ENABLE_DUMP, 181 .enable_mask = SYSRQ_ENABLE_DUMP,
190}; 182};
191 183
192static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs, 184static void sysrq_handle_showmem(int key, struct tty_struct *tty)
193 struct tty_struct *tty)
194{ 185{
195 show_mem(); 186 show_mem();
196} 187}
@@ -215,8 +206,7 @@ static void send_sig_all(int sig)
215 } 206 }
216} 207}
217 208
218static void sysrq_handle_term(int key, struct pt_regs *pt_regs, 209static void sysrq_handle_term(int key, struct tty_struct *tty)
219 struct tty_struct *tty)
220{ 210{
221 send_sig_all(SIGTERM); 211 send_sig_all(SIGTERM);
222 console_loglevel = 8; 212 console_loglevel = 8;
@@ -236,8 +226,7 @@ static void moom_callback(void *ignored)
236 226
237static DECLARE_WORK(moom_work, moom_callback, NULL); 227static DECLARE_WORK(moom_work, moom_callback, NULL);
238 228
239static void sysrq_handle_moom(int key, struct pt_regs *pt_regs, 229static void sysrq_handle_moom(int key, struct tty_struct *tty)
240 struct tty_struct *tty)
241{ 230{
242 schedule_work(&moom_work); 231 schedule_work(&moom_work);
243} 232}
@@ -247,8 +236,7 @@ static struct sysrq_key_op sysrq_moom_op = {
247 .action_msg = "Manual OOM execution", 236 .action_msg = "Manual OOM execution",
248}; 237};
249 238
250static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, 239static void sysrq_handle_kill(int key, struct tty_struct *tty)
251 struct tty_struct *tty)
252{ 240{
253 send_sig_all(SIGKILL); 241 send_sig_all(SIGKILL);
254 console_loglevel = 8; 242 console_loglevel = 8;
@@ -260,8 +248,7 @@ static struct sysrq_key_op sysrq_kill_op = {
260 .enable_mask = SYSRQ_ENABLE_SIGNAL, 248 .enable_mask = SYSRQ_ENABLE_SIGNAL,
261}; 249};
262 250
263static void sysrq_handle_unrt(int key, struct pt_regs *pt_regs, 251static void sysrq_handle_unrt(int key, struct tty_struct *tty)
264 struct tty_struct *tty)
265{ 252{
266 normalize_rt_tasks(); 253 normalize_rt_tasks();
267} 254}
@@ -361,8 +348,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
361 * This is the non-locking version of handle_sysrq. It must/can only be called 348 * This is the non-locking version of handle_sysrq. It must/can only be called
362 * by sysrq key handlers, as they are inside of the lock 349 * by sysrq key handlers, as they are inside of the lock
363 */ 350 */
364void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, 351void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
365 int check_mask)
366{ 352{
367 struct sysrq_key_op *op_p; 353 struct sysrq_key_op *op_p;
368 int orig_log_level; 354 int orig_log_level;
@@ -384,7 +370,7 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty,
384 (sysrq_enabled & op_p->enable_mask)) { 370 (sysrq_enabled & op_p->enable_mask)) {
385 printk("%s\n", op_p->action_msg); 371 printk("%s\n", op_p->action_msg);
386 console_loglevel = orig_log_level; 372 console_loglevel = orig_log_level;
387 op_p->handler(key, pt_regs, tty); 373 op_p->handler(key, tty);
388 } else { 374 } else {
389 printk("This sysrq operation is disabled.\n"); 375 printk("This sysrq operation is disabled.\n");
390 } 376 }
@@ -413,11 +399,11 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty,
413 * This function is called by the keyboard handler when SysRq is pressed 399 * This function is called by the keyboard handler when SysRq is pressed
414 * and any other keycode arrives. 400 * and any other keycode arrives.
415 */ 401 */
416void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) 402void handle_sysrq(int key, struct tty_struct *tty)
417{ 403{
418 if (!sysrq_enabled) 404 if (!sysrq_enabled)
419 return; 405 return;
420 __handle_sysrq(key, pt_regs, tty, 1); 406 __handle_sysrq(key, tty, 1);
421} 407}
422EXPORT_SYMBOL(handle_sysrq); 408EXPORT_SYMBOL(handle_sysrq);
423 409