aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
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/usb/core
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/usb/core')
-rw-r--r--drivers/usb/core/devio.c2
-rw-r--r--drivers/usb/core/hcd.c15
-rw-r--r--drivers/usb/core/hcd.h9
-rw-r--r--drivers/usb/core/hub.c2
-rw-r--r--drivers/usb/core/message.c4
5 files changed, 14 insertions, 18 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 3f509beb88e..2c9c9462d89 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -304,7 +304,7 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
304 printk("\n"); 304 printk("\n");
305} 305}
306 306
307static void async_completed(struct urb *urb, struct pt_regs *regs) 307static void async_completed(struct urb *urb)
308{ 308{
309 struct async *as = urb->context; 309 struct async *as = urb->context;
310 struct dev_state *ps = as->ps; 310 struct dev_state *ps = as->ps;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e658089f7b5..afa2dd20332 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -522,7 +522,7 @@ error:
522 if (urb->status == -EINPROGRESS) 522 if (urb->status == -EINPROGRESS)
523 urb->status = status; 523 urb->status = status;
524 spin_unlock (&urb->lock); 524 spin_unlock (&urb->lock);
525 usb_hcd_giveback_urb (hcd, urb, NULL); 525 usb_hcd_giveback_urb (hcd, urb);
526 local_irq_restore (flags); 526 local_irq_restore (flags);
527 return 0; 527 return 0;
528} 528}
@@ -572,7 +572,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
572 572
573 /* local irqs are always blocked in completions */ 573 /* local irqs are always blocked in completions */
574 if (length > 0) 574 if (length > 0)
575 usb_hcd_giveback_urb (hcd, urb, NULL); 575 usb_hcd_giveback_urb (hcd, urb);
576 else 576 else
577 hcd->poll_pending = 1; 577 hcd->poll_pending = 1;
578 local_irq_restore (flags); 578 local_irq_restore (flags);
@@ -656,7 +656,7 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
656 urb = NULL; /* wasn't fully queued */ 656 urb = NULL; /* wasn't fully queued */
657 spin_unlock (&hcd_root_hub_lock); 657 spin_unlock (&hcd_root_hub_lock);
658 if (urb) 658 if (urb)
659 usb_hcd_giveback_urb (hcd, urb, NULL); 659 usb_hcd_giveback_urb (hcd, urb);
660 local_irq_restore (flags); 660 local_irq_restore (flags);
661 } 661 }
662 662
@@ -1498,7 +1498,6 @@ EXPORT_SYMBOL (usb_bus_start_enum);
1498 * usb_hcd_giveback_urb - return URB from HCD to device driver 1498 * usb_hcd_giveback_urb - return URB from HCD to device driver
1499 * @hcd: host controller returning the URB 1499 * @hcd: host controller returning the URB
1500 * @urb: urb being returned to the USB device driver. 1500 * @urb: urb being returned to the USB device driver.
1501 * @regs: pt_regs, passed down to the URB completion handler
1502 * Context: in_interrupt() 1501 * Context: in_interrupt()
1503 * 1502 *
1504 * This hands the URB from HCD to its USB device driver, using its 1503 * This hands the URB from HCD to its USB device driver, using its
@@ -1507,7 +1506,7 @@ EXPORT_SYMBOL (usb_bus_start_enum);
1507 * the device driver won't cause problems if it frees, modifies, 1506 * the device driver won't cause problems if it frees, modifies,
1508 * or resubmits this URB. 1507 * or resubmits this URB.
1509 */ 1508 */
1510void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) 1509void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
1511{ 1510{
1512 int at_root_hub; 1511 int at_root_hub;
1513 1512
@@ -1534,7 +1533,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs
1534 1533
1535 usbmon_urb_complete (&hcd->self, urb); 1534 usbmon_urb_complete (&hcd->self, urb);
1536 /* pass ownership to the completion handler */ 1535 /* pass ownership to the completion handler */
1537 urb->complete (urb, regs); 1536 urb->complete (urb);
1538 atomic_dec (&urb->use_count); 1537 atomic_dec (&urb->use_count);
1539 if (unlikely (urb->reject)) 1538 if (unlikely (urb->reject))
1540 wake_up (&usb_kill_urb_queue); 1539 wake_up (&usb_kill_urb_queue);
@@ -1553,7 +1552,7 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
1553 * If the controller isn't HALTed, calls the driver's irq handler. 1552 * If the controller isn't HALTed, calls the driver's irq handler.
1554 * Checks whether the controller is now dead. 1553 * Checks whether the controller is now dead.
1555 */ 1554 */
1556irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) 1555irqreturn_t usb_hcd_irq (int irq, void *__hcd)
1557{ 1556{
1558 struct usb_hcd *hcd = __hcd; 1557 struct usb_hcd *hcd = __hcd;
1559 int start = hcd->state; 1558 int start = hcd->state;
@@ -1561,7 +1560,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
1561 if (unlikely(start == HC_STATE_HALT || 1560 if (unlikely(start == HC_STATE_HALT ||
1562 !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) 1561 !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
1563 return IRQ_NONE; 1562 return IRQ_NONE;
1564 if (hcd->driver->irq (hcd, r) == IRQ_NONE) 1563 if (hcd->driver->irq (hcd) == IRQ_NONE)
1565 return IRQ_NONE; 1564 return IRQ_NONE;
1566 1565
1567 set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); 1566 set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 676877c15f8..8f8df0d4382 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -143,15 +143,13 @@ struct hcd_timeout { /* timeouts we allocate */
143/*-------------------------------------------------------------------------*/ 143/*-------------------------------------------------------------------------*/
144 144
145 145
146struct pt_regs;
147
148struct hc_driver { 146struct hc_driver {
149 const char *description; /* "ehci-hcd" etc */ 147 const char *description; /* "ehci-hcd" etc */
150 const char *product_desc; /* product/vendor string */ 148 const char *product_desc; /* product/vendor string */
151 size_t hcd_priv_size; /* size of private data */ 149 size_t hcd_priv_size; /* size of private data */
152 150
153 /* irq handler */ 151 /* irq handler */
154 irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs); 152 irqreturn_t (*irq) (struct usb_hcd *hcd);
155 153
156 int flags; 154 int flags;
157#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ 155#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
@@ -205,8 +203,7 @@ struct hc_driver {
205 203
206extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); 204extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
207extern int usb_hcd_unlink_urb (struct urb *urb, int status); 205extern int usb_hcd_unlink_urb (struct urb *urb, int status);
208extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, 206extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
209 struct pt_regs *regs);
210extern void usb_hcd_endpoint_disable (struct usb_device *udev, 207extern void usb_hcd_endpoint_disable (struct usb_device *udev,
211 struct usb_host_endpoint *ep); 208 struct usb_host_endpoint *ep);
212extern int usb_hcd_get_frame_number (struct usb_device *udev); 209extern int usb_hcd_get_frame_number (struct usb_device *udev);
@@ -248,7 +245,7 @@ void hcd_buffer_free (struct usb_bus *bus, size_t size,
248 void *addr, dma_addr_t dma); 245 void *addr, dma_addr_t dma);
249 246
250/* generic bus glue, needed for host controllers that don't use PCI */ 247/* generic bus glue, needed for host controllers that don't use PCI */
251extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r); 248extern irqreturn_t usb_hcd_irq (int irq, void *__hcd);
252 249
253extern void usb_hc_died (struct usb_hcd *hcd); 250extern void usb_hc_died (struct usb_hcd *hcd);
254extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); 251extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 7676690a038..66bff184a30 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -291,7 +291,7 @@ void usb_kick_khubd(struct usb_device *hdev)
291 291
292 292
293/* completion function, fires on port status changes and various faults */ 293/* completion function, fires on port status changes and various faults */
294static void hub_irq(struct urb *urb, struct pt_regs *regs) 294static void hub_irq(struct urb *urb)
295{ 295{
296 struct usb_hub *hub = urb->context; 296 struct usb_hub *hub = urb->context;
297 int status; 297 int status;
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 85b1cd18336..fccd1952bad 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -17,7 +17,7 @@
17#include "hcd.h" /* for usbcore internals */ 17#include "hcd.h" /* for usbcore internals */
18#include "usb.h" 18#include "usb.h"
19 19
20static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) 20static void usb_api_blocking_completion(struct urb *urb)
21{ 21{
22 complete((struct completion *)urb->context); 22 complete((struct completion *)urb->context);
23} 23}
@@ -246,7 +246,7 @@ static void sg_clean (struct usb_sg_request *io)
246 io->dev = NULL; 246 io->dev = NULL;
247} 247}
248 248
249static void sg_complete (struct urb *urb, struct pt_regs *regs) 249static void sg_complete (struct urb *urb)
250{ 250{
251 struct usb_sg_request *io = urb->context; 251 struct usb_sg_request *io = urb->context;
252 252