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)
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 3df5eed..5a7b49c 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -37,14 +37,14 @@
 	unsigned int		open;
 };
 
-static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t amba_kmi_int(int irq, void *dev_id)
 {
 	struct amba_kmi_port *kmi = dev_id;
 	unsigned int status = readb(KMIIR);
 	int handled = IRQ_NONE;
 
 	while (status & KMIIR_RXINTR) {
-		serio_interrupt(kmi->io, readb(KMIDATA), 0, regs);
+		serio_interrupt(kmi->io, readb(KMIDATA), 0);
 		status = readb(KMIIR);
 		handled = IRQ_HANDLED;
 	}
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
index bc6e87a..0d35018 100644
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -71,9 +71,9 @@
  * is waiting in the 82C710.
  */
 
-static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
+static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id)
 {
-	return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs);
+	return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0);
 }
 
 /*
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index cde036a..081fdc3 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -82,7 +82,7 @@
 #define GSC_ID_MOUSE		1
 
 
-static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs);
+static irqreturn_t gscps2_interrupt(int irq, void *dev);
 
 #define BUFFER_SIZE 0x0f
 
@@ -226,7 +226,7 @@
  * later.
  */
 
-static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t gscps2_interrupt(int irq, void *dev)
 {
 	struct gscps2port *ps2port;
 
@@ -267,7 +267,7 @@
 	    rxflags =	((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) |
 			((status & GSC_STAT_PERR) ? SERIO_PARITY  : 0 );
 
-	    serio_interrupt(ps2port->port, data, rxflags, regs);
+	    serio_interrupt(ps2port->port, data, rxflags);
 
 	  } /* while() */
 
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index a10348b..ba7b920 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -202,7 +202,7 @@
 	}
 }
 
-static irqreturn_t hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) {
+static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
 	uint8_t status, data;
 
 	status = hp_sdc_status_in8();
@@ -253,7 +253,7 @@
 }
 
 
-static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id, struct pt_regs * regs) {
+static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
 	int status;
 	
 	status = hp_sdc_status_in8();
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 1bb0c76..09b06e6 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -108,7 +108,7 @@
 static unsigned char i8042_aux_irq_registered;
 static struct platform_device *i8042_platform_device;
 
-static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t i8042_interrupt(int irq, void *dev_id);
 
 /*
  * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
@@ -271,7 +271,7 @@
  * characters later.
  */
 
-	i8042_interrupt(0, NULL, NULL);
+	i8042_interrupt(0, NULL);
 	return retval;
 }
 
@@ -309,7 +309,7 @@
  * to the upper layers.
  */
 
-static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i8042_interrupt(int irq, void *dev_id)
 {
 	struct i8042_port *port;
 	unsigned long flags;
@@ -379,7 +379,7 @@
 	    dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
 	if (likely(port->exists))
-		serio_interrupt(port->serio, data, dfl, regs);
+		serio_interrupt(port->serio, data, dfl);
 
 	ret = 1;
  out:
@@ -519,7 +519,7 @@
 static struct completion i8042_aux_irq_delivered __devinitdata;
 static int i8042_irq_being_tested __devinitdata;
 
-static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id)
 {
 	unsigned long flags;
 	unsigned char str, data;
@@ -905,7 +905,7 @@
 	if (i8042_ports[I8042_KBD_PORT_NO].serio)
 		i8042_enable_kbd_port();
 
-	i8042_interrupt(0, NULL, NULL);
+	i8042_interrupt(0, NULL);
 
 	return 0;
 }
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
index f08a5d0..558200e 100644
--- a/drivers/input/serio/maceps2.c
+++ b/drivers/input/serio/maceps2.c
@@ -72,8 +72,7 @@
 	return -1;
 }
 
-static irqreturn_t maceps2_interrupt(int irq, void *dev_id,
-				     struct pt_regs *regs)
+static irqreturn_t maceps2_interrupt(int irq, void *dev_id)
 {
 	struct serio *dev = dev_id;
 	struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port;
@@ -81,7 +80,7 @@
 
 	if (port->status & PS2_STATUS_RX_FULL) {
 		byte = port->rx;
-		serio_interrupt(dev, byte & 0xff, 0, regs);
+		serio_interrupt(dev, byte & 0xff, 0);
         }
 
 	return IRQ_HANDLED;
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
index a5c1fb3..688610e 100644
--- a/drivers/input/serio/parkbd.c
+++ b/drivers/input/serio/parkbd.c
@@ -102,7 +102,7 @@
 	return 0;
 }
 
-static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void parkbd_interrupt(int irq, void *dev_id)
 {
 
 	if (parkbd_writing) {
@@ -134,7 +134,7 @@
 		parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
 
 		if (parkbd_counter == parkbd_mode + 10)
-			serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs);
+			serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
 	}
 
 	parkbd_last = jiffies;
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index fb727c6..ea5e3c6 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -58,7 +58,7 @@
 	return 0;
 }
 
-static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t pcips2_interrupt(int irq, void *devid)
 {
 	struct pcips2_data *ps2if = devid;
 	unsigned char status, scancode;
@@ -80,7 +80,7 @@
 		if (hweight8(scancode) & 1)
 			flag ^= SERIO_PARITY;
 
-		serio_interrupt(ps2if->io, scancode, flag, regs);
+		serio_interrupt(ps2if->io, scancode, flag);
 	} while (1);
 	return IRQ_RETVAL(handled);
 }
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index d3827c5..cb89aff 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -53,14 +53,14 @@
 static struct serio *q40kbd_port;
 static struct platform_device *q40kbd_device;
 
-static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&q40kbd_lock, flags);
 
 	if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
-		serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs);
+		serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0);
 
 	master_outb(-1, KEYBOARD_UNLOCK_REG);
 
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index 513d37f..49f8431 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -56,7 +56,7 @@
 	return 0;
 }
 
-static irqreturn_t rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rpckbd_rx(int irq, void *dev_id)
 {
 	struct serio *port = dev_id;
 	unsigned int byte;
@@ -65,13 +65,13 @@
 	while (iomd_readb(IOMD_KCTRL) & (1 << 5)) {
 		byte = iomd_readb(IOMD_KARTRX);
 
-		serio_interrupt(port, byte, 0, regs);
+		serio_interrupt(port, byte, 0);
 		handled = IRQ_HANDLED;
 	}
 	return handled;
 }
 
-static irqreturn_t rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rpckbd_tx(int irq, void *dev_id)
 {
 	return IRQ_HANDLED;
 }
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index ebd9976..5595087 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -40,7 +40,7 @@
  * at the most one, but we loop for safety.  If there was a
  * framing error, we have to manually clear the status.
  */
-static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ps2_rxint(int irq, void *dev_id)
 {
 	struct ps2if *ps2if = dev_id;
 	unsigned int scancode, flag, status;
@@ -58,7 +58,7 @@
 		if (hweight8(scancode) & 1)
 			flag ^= SERIO_PARITY;
 
-		serio_interrupt(ps2if->io, scancode, flag, regs);
+		serio_interrupt(ps2if->io, scancode, flag);
 
 		status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
         }
@@ -69,7 +69,7 @@
 /*
  * Completion of ps2 write
  */
-static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ps2_txint(int irq, void *dev_id)
 {
 	struct ps2if *ps2if = dev_id;
 	unsigned int status;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 3e76ad7..960fae3 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -911,7 +911,7 @@
 }
 
 irqreturn_t serio_interrupt(struct serio *serio,
-		unsigned char data, unsigned int dfl, struct pt_regs *regs)
+		unsigned char data, unsigned int dfl)
 {
 	unsigned long flags;
 	irqreturn_t ret = IRQ_NONE;
@@ -919,7 +919,7 @@
 	spin_lock_irqsave(&serio->lock, flags);
 
         if (likely(serio->drv)) {
-                ret = serio->drv->interrupt(serio, data, dfl, regs);
+                ret = serio->drv->interrupt(serio, data, dfl);
 	} else if (!dfl && serio->registered) {
 		serio_rescan(serio);
 		ret = IRQ_HANDLED;
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 71a8eea..ba2a203 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -250,7 +250,7 @@
  *********************************************************************/
 
 static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
-					unsigned int dfl, struct pt_regs *regs)
+					unsigned int dfl)
 {
 	struct serio_raw *serio_raw = serio_get_drvdata(serio);
 	struct serio_raw_list *list;
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 54a680c..e1a3a79 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -117,9 +117,6 @@
  * serport_ldisc_receive() is called by the low level tty driver when characters
  * are ready for us. We forward the characters, one by one to the 'interrupt'
  * routine.
- *
- * FIXME: We should get pt_regs from the tty layer and forward them to
- *	  serio_interrupt here.
  */
 
 static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
@@ -134,7 +131,7 @@
 		goto out;
 
 	for (i = 0; i < count; i++)
-		serio_interrupt(serport->serio, cp[i], 0, NULL);
+		serio_interrupt(serport->serio, cp[i], 0);
 
 out:
 	spin_unlock_irqrestore(&serport->lock, flags);