aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/input/hid-core.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/usb/input/hid-core.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/usb/input/hid-core.c')
-rw-r--r--drivers/usb/input/hid-core.c28
1 files changed, 14 insertions, 14 deletions
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index e0fd11605b43..a6738a83ff5b 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -780,13 +780,13 @@ static __inline__ int search(__s32 *array, __s32 value, unsigned n)
780 return -1; 780 return -1;
781} 781}
782 782
783static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt, struct pt_regs *regs) 783static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
784{ 784{
785 hid_dump_input(usage, value); 785 hid_dump_input(usage, value);
786 if (hid->claimed & HID_CLAIMED_INPUT) 786 if (hid->claimed & HID_CLAIMED_INPUT)
787 hidinput_hid_event(hid, field, usage, value, regs); 787 hidinput_hid_event(hid, field, usage, value);
788 if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt) 788 if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)
789 hiddev_hid_event(hid, field, usage, value, regs); 789 hiddev_hid_event(hid, field, usage, value);
790} 790}
791 791
792/* 792/*
@@ -795,7 +795,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s
795 * reporting to the layer). 795 * reporting to the layer).
796 */ 796 */
797 797
798static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt, struct pt_regs *regs) 798static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
799{ 799{
800 unsigned n; 800 unsigned n;
801 unsigned count = field->report_count; 801 unsigned count = field->report_count;
@@ -822,19 +822,19 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u
822 for (n = 0; n < count; n++) { 822 for (n = 0; n < count; n++) {
823 823
824 if (HID_MAIN_ITEM_VARIABLE & field->flags) { 824 if (HID_MAIN_ITEM_VARIABLE & field->flags) {
825 hid_process_event(hid, field, &field->usage[n], value[n], interrupt, regs); 825 hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
826 continue; 826 continue;
827 } 827 }
828 828
829 if (field->value[n] >= min && field->value[n] <= max 829 if (field->value[n] >= min && field->value[n] <= max
830 && field->usage[field->value[n] - min].hid 830 && field->usage[field->value[n] - min].hid
831 && search(value, field->value[n], count)) 831 && search(value, field->value[n], count))
832 hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt, regs); 832 hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
833 833
834 if (value[n] >= min && value[n] <= max 834 if (value[n] >= min && value[n] <= max
835 && field->usage[value[n] - min].hid 835 && field->usage[value[n] - min].hid
836 && search(field->value, value[n], count)) 836 && search(field->value, value[n], count))
837 hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt, regs); 837 hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
838 } 838 }
839 839
840 memcpy(field->value, value, count * sizeof(__s32)); 840 memcpy(field->value, value, count * sizeof(__s32));
@@ -842,7 +842,7 @@ exit:
842 kfree(value); 842 kfree(value);
843} 843}
844 844
845static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_regs *regs) 845static int hid_input_report(int type, struct urb *urb, int interrupt)
846{ 846{
847 struct hid_device *hid = urb->context; 847 struct hid_device *hid = urb->context;
848 struct hid_report_enum *report_enum = hid->report_enum + type; 848 struct hid_report_enum *report_enum = hid->report_enum + type;
@@ -892,7 +892,7 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_
892 hiddev_report_event(hid, report); 892 hiddev_report_event(hid, report);
893 893
894 for (n = 0; n < report->maxfield; n++) 894 for (n = 0; n < report->maxfield; n++)
895 hid_input_field(hid, report->field[n], data, interrupt, regs); 895 hid_input_field(hid, report->field[n], data, interrupt);
896 896
897 if (hid->claimed & HID_CLAIMED_INPUT) 897 if (hid->claimed & HID_CLAIMED_INPUT)
898 hidinput_report_event(hid, report); 898 hidinput_report_event(hid, report);
@@ -1004,7 +1004,7 @@ done:
1004 * Input interrupt completion handler. 1004 * Input interrupt completion handler.
1005 */ 1005 */
1006 1006
1007static void hid_irq_in(struct urb *urb, struct pt_regs *regs) 1007static void hid_irq_in(struct urb *urb)
1008{ 1008{
1009 struct hid_device *hid = urb->context; 1009 struct hid_device *hid = urb->context;
1010 int status; 1010 int status;
@@ -1012,7 +1012,7 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
1012 switch (urb->status) { 1012 switch (urb->status) {
1013 case 0: /* success */ 1013 case 0: /* success */
1014 hid->retry_delay = 0; 1014 hid->retry_delay = 0;
1015 hid_input_report(HID_INPUT_REPORT, urb, 1, regs); 1015 hid_input_report(HID_INPUT_REPORT, urb, 1);
1016 break; 1016 break;
1017 case -ECONNRESET: /* unlink */ 1017 case -ECONNRESET: /* unlink */
1018 case -ENOENT: 1018 case -ENOENT:
@@ -1193,7 +1193,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
1193 * Output interrupt completion handler. 1193 * Output interrupt completion handler.
1194 */ 1194 */
1195 1195
1196static void hid_irq_out(struct urb *urb, struct pt_regs *regs) 1196static void hid_irq_out(struct urb *urb)
1197{ 1197{
1198 struct hid_device *hid = urb->context; 1198 struct hid_device *hid = urb->context;
1199 unsigned long flags; 1199 unsigned long flags;
@@ -1238,7 +1238,7 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
1238 * Control pipe completion handler. 1238 * Control pipe completion handler.
1239 */ 1239 */
1240 1240
1241static void hid_ctrl(struct urb *urb, struct pt_regs *regs) 1241static void hid_ctrl(struct urb *urb)
1242{ 1242{
1243 struct hid_device *hid = urb->context; 1243 struct hid_device *hid = urb->context;
1244 unsigned long flags; 1244 unsigned long flags;
@@ -1249,7 +1249,7 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
1249 switch (urb->status) { 1249 switch (urb->status) {
1250 case 0: /* success */ 1250 case 0: /* success */
1251 if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) 1251 if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN)
1252 hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs); 1252 hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0);
1253 break; 1253 break;
1254 case -ESHUTDOWN: /* unplug */ 1254 case -ESHUTDOWN: /* unplug */
1255 unplug = 1; 1255 unplug = 1;