aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/forcedeth.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/net/forcedeth.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/net/forcedeth.c')
-rw-r--r--drivers/net/forcedeth.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index eea1d66c530e..99b7a411db28 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -2397,7 +2397,7 @@ static void nv_link_irq(struct net_device *dev)
2397 dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name); 2397 dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name);
2398} 2398}
2399 2399
2400static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) 2400static irqreturn_t nv_nic_irq(int foo, void *data)
2401{ 2401{
2402 struct net_device *dev = (struct net_device *) data; 2402 struct net_device *dev = (struct net_device *) data;
2403 struct fe_priv *np = netdev_priv(dev); 2403 struct fe_priv *np = netdev_priv(dev);
@@ -2490,7 +2490,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
2490 return IRQ_RETVAL(i); 2490 return IRQ_RETVAL(i);
2491} 2491}
2492 2492
2493static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) 2493static irqreturn_t nv_nic_irq_tx(int foo, void *data)
2494{ 2494{
2495 struct net_device *dev = (struct net_device *) data; 2495 struct net_device *dev = (struct net_device *) data;
2496 struct fe_priv *np = netdev_priv(dev); 2496 struct fe_priv *np = netdev_priv(dev);
@@ -2576,7 +2576,7 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
2576#endif 2576#endif
2577 2577
2578#ifdef CONFIG_FORCEDETH_NAPI 2578#ifdef CONFIG_FORCEDETH_NAPI
2579static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) 2579static irqreturn_t nv_nic_irq_rx(int foo, void *data)
2580{ 2580{
2581 struct net_device *dev = (struct net_device *) data; 2581 struct net_device *dev = (struct net_device *) data;
2582 u8 __iomem *base = get_hwbase(dev); 2582 u8 __iomem *base = get_hwbase(dev);
@@ -2594,7 +2594,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
2594 return IRQ_HANDLED; 2594 return IRQ_HANDLED;
2595} 2595}
2596#else 2596#else
2597static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) 2597static irqreturn_t nv_nic_irq_rx(int foo, void *data)
2598{ 2598{
2599 struct net_device *dev = (struct net_device *) data; 2599 struct net_device *dev = (struct net_device *) data;
2600 struct fe_priv *np = netdev_priv(dev); 2600 struct fe_priv *np = netdev_priv(dev);
@@ -2641,7 +2641,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
2641} 2641}
2642#endif 2642#endif
2643 2643
2644static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) 2644static irqreturn_t nv_nic_irq_other(int foo, void *data)
2645{ 2645{
2646 struct net_device *dev = (struct net_device *) data; 2646 struct net_device *dev = (struct net_device *) data;
2647 struct fe_priv *np = netdev_priv(dev); 2647 struct fe_priv *np = netdev_priv(dev);
@@ -2695,7 +2695,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
2695 return IRQ_RETVAL(i); 2695 return IRQ_RETVAL(i);
2696} 2696}
2697 2697
2698static irqreturn_t nv_nic_irq_test(int foo, void *data, struct pt_regs *regs) 2698static irqreturn_t nv_nic_irq_test(int foo, void *data)
2699{ 2699{
2700 struct net_device *dev = (struct net_device *) data; 2700 struct net_device *dev = (struct net_device *) data;
2701 struct fe_priv *np = netdev_priv(dev); 2701 struct fe_priv *np = netdev_priv(dev);
@@ -2905,22 +2905,22 @@ static void nv_do_nic_poll(unsigned long data)
2905 pci_push(base); 2905 pci_push(base);
2906 2906
2907 if (!using_multi_irqs(dev)) { 2907 if (!using_multi_irqs(dev)) {
2908 nv_nic_irq(0, dev, NULL); 2908 nv_nic_irq(0, dev);
2909 if (np->msi_flags & NV_MSI_X_ENABLED) 2909 if (np->msi_flags & NV_MSI_X_ENABLED)
2910 enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); 2910 enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
2911 else 2911 else
2912 enable_irq_lockdep(dev->irq); 2912 enable_irq_lockdep(dev->irq);
2913 } else { 2913 } else {
2914 if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { 2914 if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
2915 nv_nic_irq_rx(0, dev, NULL); 2915 nv_nic_irq_rx(0, dev);
2916 enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); 2916 enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
2917 } 2917 }
2918 if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) { 2918 if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) {
2919 nv_nic_irq_tx(0, dev, NULL); 2919 nv_nic_irq_tx(0, dev);
2920 enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); 2920 enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
2921 } 2921 }
2922 if (np->nic_poll_irq & NVREG_IRQ_OTHER) { 2922 if (np->nic_poll_irq & NVREG_IRQ_OTHER) {
2923 nv_nic_irq_other(0, dev, NULL); 2923 nv_nic_irq_other(0, dev);
2924 enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); 2924 enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
2925 } 2925 }
2926 } 2926 }