aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/arm
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/net/arm
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/net/arm')
-rw-r--r--drivers/net/arm/am79c961a.c4
-rw-r--r--drivers/net/arm/at91_ether.c4
-rw-r--r--drivers/net/arm/ep93xx_eth.c2
-rw-r--r--drivers/net/arm/ether1.c4
-rw-r--r--drivers/net/arm/ether3.c4
5 files changed, 9 insertions, 9 deletions
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 09d5c3f26985..ddd12d44ff22 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -38,7 +38,7 @@
38#include "am79c961a.h" 38#include "am79c961a.h"
39 39
40static irqreturn_t 40static irqreturn_t
41am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs); 41am79c961_interrupt (int irq, void *dev_id);
42 42
43static unsigned int net_debug = NET_DEBUG; 43static unsigned int net_debug = NET_DEBUG;
44 44
@@ -596,7 +596,7 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
596} 596}
597 597
598static irqreturn_t 598static irqreturn_t
599am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) 599am79c961_interrupt(int irq, void *dev_id)
600{ 600{
601 struct net_device *dev = (struct net_device *)dev_id; 601 struct net_device *dev = (struct net_device *)dev_id;
602 struct dev_priv *priv = netdev_priv(dev); 602 struct dev_priv *priv = netdev_priv(dev);
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 3ecf2cc53a7c..b54b857e357e 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -196,7 +196,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
196/* 196/*
197 * Handle interrupts from the PHY 197 * Handle interrupts from the PHY
198 */ 198 */
199static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) 199static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
200{ 200{
201 struct net_device *dev = (struct net_device *) dev_id; 201 struct net_device *dev = (struct net_device *) dev_id;
202 struct at91_private *lp = (struct at91_private *) dev->priv; 202 struct at91_private *lp = (struct at91_private *) dev->priv;
@@ -888,7 +888,7 @@ static void at91ether_rx(struct net_device *dev)
888/* 888/*
889 * MAC interrupt handler 889 * MAC interrupt handler
890 */ 890 */
891static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs) 891static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
892{ 892{
893 struct net_device *dev = (struct net_device *) dev_id; 893 struct net_device *dev = (struct net_device *) dev_id;
894 struct at91_private *lp = (struct at91_private *) dev->priv; 894 struct at91_private *lp = (struct at91_private *) dev->priv;
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index d231efa624d4..127561c782fd 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -435,7 +435,7 @@ static void ep93xx_tx_complete(struct net_device *dev)
435 netif_wake_queue(dev); 435 netif_wake_queue(dev);
436} 436}
437 437
438static irqreturn_t ep93xx_irq(int irq, void *dev_id, struct pt_regs *regs) 438static irqreturn_t ep93xx_irq(int irq, void *dev_id)
439{ 439{
440 struct net_device *dev = dev_id; 440 struct net_device *dev = dev_id;
441 struct ep93xx_priv *ep = netdev_priv(dev); 441 struct ep93xx_priv *ep = netdev_priv(dev);
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index 312955d07b28..f3478a30e778 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -68,7 +68,7 @@ static unsigned int net_debug = NET_DEBUG;
68 68
69static int ether1_open(struct net_device *dev); 69static int ether1_open(struct net_device *dev);
70static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev); 70static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
71static irqreturn_t ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs); 71static irqreturn_t ether1_interrupt(int irq, void *dev_id);
72static int ether1_close(struct net_device *dev); 72static int ether1_close(struct net_device *dev);
73static struct net_device_stats *ether1_getstats(struct net_device *dev); 73static struct net_device_stats *ether1_getstats(struct net_device *dev);
74static void ether1_setmulticastlist(struct net_device *dev); 74static void ether1_setmulticastlist(struct net_device *dev);
@@ -908,7 +908,7 @@ ether1_recv_done (struct net_device *dev)
908} 908}
909 909
910static irqreturn_t 910static irqreturn_t
911ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs) 911ether1_interrupt (int irq, void *dev_id)
912{ 912{
913 struct net_device *dev = (struct net_device *)dev_id; 913 struct net_device *dev = (struct net_device *)dev_id;
914 int status; 914 int status;
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 081074180e62..84686c8a5bc2 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -81,7 +81,7 @@ static int ether3_rx(struct net_device *dev, unsigned int maxcnt);
81static void ether3_tx(struct net_device *dev); 81static void ether3_tx(struct net_device *dev);
82static int ether3_open (struct net_device *dev); 82static int ether3_open (struct net_device *dev);
83static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev); 83static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
84static irqreturn_t ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs); 84static irqreturn_t ether3_interrupt (int irq, void *dev_id);
85static int ether3_close (struct net_device *dev); 85static int ether3_close (struct net_device *dev);
86static struct net_device_stats *ether3_getstats (struct net_device *dev); 86static struct net_device_stats *ether3_getstats (struct net_device *dev);
87static void ether3_setmulticastlist (struct net_device *dev); 87static void ether3_setmulticastlist (struct net_device *dev);
@@ -568,7 +568,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
568} 568}
569 569
570static irqreturn_t 570static irqreturn_t
571ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs) 571ether3_interrupt(int irq, void *dev_id)
572{ 572{
573 struct net_device *dev = (struct net_device *)dev_id; 573 struct net_device *dev = (struct net_device *)dev_id;
574 unsigned int status, handled = IRQ_NONE; 574 unsigned int status, handled = IRQ_NONE;