aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-09-11 13:28:30 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-09-12 02:41:18 -0400
commit76460a7becadbda5589057ee8394cbc98717c324 (patch)
tree20acc49eb856fa49c321e3616424f166fc5053a7
parenta3b3ca753cdc92c7d5f57404afed3115b3b79cc6 (diff)
Input: joystick - use ktime for measuring timing
The current codes in gameport and analog joystick drivers for the time accounting have a long-standing problem when the system is running with CPU freq; since the timing is measured via TSC or sample counter, the calculation isn't reliable. In this patch, as a simple fix, use the standard ktime to measure the timing. In case where no high resolution timer is available, use_ktime bool option is provided to both modules. Setting use_ktime=false switches to the old methods. Tested-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/gameport/gameport.c41
-rw-r--r--drivers/input/joystick/analog.c71
2 files changed, 92 insertions, 20 deletions
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 24c41ba7d4e0..e29c04e2aff4 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -23,6 +23,7 @@
23#include <linux/workqueue.h> 23#include <linux/workqueue.h>
24#include <linux/sched.h> /* HZ */ 24#include <linux/sched.h> /* HZ */
25#include <linux/mutex.h> 25#include <linux/mutex.h>
26#include <linux/timekeeping.h>
26 27
27/*#include <asm/io.h>*/ 28/*#include <asm/io.h>*/
28 29
@@ -30,6 +31,10 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
30MODULE_DESCRIPTION("Generic gameport layer"); 31MODULE_DESCRIPTION("Generic gameport layer");
31MODULE_LICENSE("GPL"); 32MODULE_LICENSE("GPL");
32 33
34static bool use_ktime = true;
35module_param(use_ktime, bool, 0400);
36MODULE_PARM_DESC(use_ktime, "Use ktime for measuring I/O speed");
37
33/* 38/*
34 * gameport_mutex protects entire gameport subsystem and is taken 39 * gameport_mutex protects entire gameport subsystem and is taken
35 * every time gameport port or driver registrered or unregistered. 40 * every time gameport port or driver registrered or unregistered.
@@ -76,6 +81,38 @@ static unsigned int get_time_pit(void)
76 81
77static int gameport_measure_speed(struct gameport *gameport) 82static int gameport_measure_speed(struct gameport *gameport)
78{ 83{
84 unsigned int i, t, tx;
85 u64 t1, t2, t3;
86 unsigned long flags;
87
88 if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
89 return 0;
90
91 tx = ~0;
92
93 for (i = 0; i < 50; i++) {
94 local_irq_save(flags);
95 t1 = ktime_get_ns();
96 for (t = 0; t < 50; t++)
97 gameport_read(gameport);
98 t2 = ktime_get_ns();
99 t3 = ktime_get_ns();
100 local_irq_restore(flags);
101 udelay(i * 10);
102 t = (t2 - t1) - (t3 - t2);
103 if (t < tx)
104 tx = t;
105 }
106
107 gameport_close(gameport);
108 t = 1000000 * 50;
109 if (tx)
110 t /= tx;
111 return t;
112}
113
114static int old_gameport_measure_speed(struct gameport *gameport)
115{
79#if defined(__i386__) 116#if defined(__i386__)
80 117
81 unsigned int i, t, t1, t2, t3, tx; 118 unsigned int i, t, t1, t2, t3, tx;
@@ -521,7 +558,9 @@ static void gameport_add_port(struct gameport *gameport)
521 if (gameport->parent) 558 if (gameport->parent)
522 gameport->parent->child = gameport; 559 gameport->parent->child = gameport;
523 560
524 gameport->speed = gameport_measure_speed(gameport); 561 gameport->speed = use_ktime ?
562 gameport_measure_speed(gameport) :
563 old_gameport_measure_speed(gameport);
525 564
526 list_add_tail(&gameport->node, &gameport_list); 565 list_add_tail(&gameport->node, &gameport_list);
527 566
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index ab0fdcd36e18..4284080e481d 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -36,6 +36,7 @@
36#include <linux/gameport.h> 36#include <linux/gameport.h>
37#include <linux/jiffies.h> 37#include <linux/jiffies.h>
38#include <linux/timex.h> 38#include <linux/timex.h>
39#include <linux/timekeeping.h>
39 40
40#define DRIVER_DESC "Analog joystick and gamepad driver" 41#define DRIVER_DESC "Analog joystick and gamepad driver"
41 42
@@ -43,6 +44,10 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
43MODULE_DESCRIPTION(DRIVER_DESC); 44MODULE_DESCRIPTION(DRIVER_DESC);
44MODULE_LICENSE("GPL"); 45MODULE_LICENSE("GPL");
45 46
47static bool use_ktime = true;
48module_param(use_ktime, bool, 0400);
49MODULE_PARM_DESC(use_ktime, "Use ktime for measuring I/O speed");
50
46/* 51/*
47 * Option parsing. 52 * Option parsing.
48 */ 53 */
@@ -171,6 +176,25 @@ static unsigned long analog_faketime = 0;
171#warning Precise timer not defined for this architecture. 176#warning Precise timer not defined for this architecture.
172#endif 177#endif
173 178
179static inline u64 get_time(void)
180{
181 if (use_ktime) {
182 return ktime_get_ns();
183 } else {
184 unsigned int x;
185 GET_TIME(x);
186 return x;
187 }
188}
189
190static inline unsigned int delta(u64 x, u64 y)
191{
192 if (use_ktime)
193 return y - x;
194 else
195 return DELTA((unsigned int)x, (unsigned int)y);
196}
197
174/* 198/*
175 * analog_decode() decodes analog joystick data and reports input events. 199 * analog_decode() decodes analog joystick data and reports input events.
176 */ 200 */
@@ -226,7 +250,8 @@ static void analog_decode(struct analog *analog, int *axes, int *initial, int bu
226static int analog_cooked_read(struct analog_port *port) 250static int analog_cooked_read(struct analog_port *port)
227{ 251{
228 struct gameport *gameport = port->gameport; 252 struct gameport *gameport = port->gameport;
229 unsigned int time[4], start, loop, now, loopout, timeout; 253 u64 time[4], start, loop, now;
254 unsigned int loopout, timeout;
230 unsigned char data[4], this, last; 255 unsigned char data[4], this, last;
231 unsigned long flags; 256 unsigned long flags;
232 int i, j; 257 int i, j;
@@ -236,7 +261,7 @@ static int analog_cooked_read(struct analog_port *port)
236 261
237 local_irq_save(flags); 262 local_irq_save(flags);
238 gameport_trigger(gameport); 263 gameport_trigger(gameport);
239 GET_TIME(now); 264 now = get_time();
240 local_irq_restore(flags); 265 local_irq_restore(flags);
241 266
242 start = now; 267 start = now;
@@ -249,16 +274,16 @@ static int analog_cooked_read(struct analog_port *port)
249 274
250 local_irq_disable(); 275 local_irq_disable();
251 this = gameport_read(gameport) & port->mask; 276 this = gameport_read(gameport) & port->mask;
252 GET_TIME(now); 277 now = get_time();
253 local_irq_restore(flags); 278 local_irq_restore(flags);
254 279
255 if ((last ^ this) && (DELTA(loop, now) < loopout)) { 280 if ((last ^ this) && (delta(loop, now) < loopout)) {
256 data[i] = last ^ this; 281 data[i] = last ^ this;
257 time[i] = now; 282 time[i] = now;
258 i++; 283 i++;
259 } 284 }
260 285
261 } while (this && (i < 4) && (DELTA(start, now) < timeout)); 286 } while (this && (i < 4) && (delta(start, now) < timeout));
262 287
263 this <<= 4; 288 this <<= 4;
264 289
@@ -266,7 +291,7 @@ static int analog_cooked_read(struct analog_port *port)
266 this |= data[i]; 291 this |= data[i];
267 for (j = 0; j < 4; j++) 292 for (j = 0; j < 4; j++)
268 if (data[i] & (1 << j)) 293 if (data[i] & (1 << j))
269 port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop; 294 port->axes[j] = (delta(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop;
270 } 295 }
271 296
272 return -(this != port->mask); 297 return -(this != port->mask);
@@ -365,31 +390,39 @@ static void analog_close(struct input_dev *dev)
365static void analog_calibrate_timer(struct analog_port *port) 390static void analog_calibrate_timer(struct analog_port *port)
366{ 391{
367 struct gameport *gameport = port->gameport; 392 struct gameport *gameport = port->gameport;
368 unsigned int i, t, tx, t1, t2, t3; 393 unsigned int i, t, tx;
394 u64 t1, t2, t3;
369 unsigned long flags; 395 unsigned long flags;
370 396
371 local_irq_save(flags); 397 if (use_ktime) {
372 GET_TIME(t1); 398 port->speed = 1000000;
399 } else {
400 local_irq_save(flags);
401 t1 = get_time();
373#ifdef FAKE_TIME 402#ifdef FAKE_TIME
374 analog_faketime += 830; 403 analog_faketime += 830;
375#endif 404#endif
376 mdelay(1); 405 mdelay(1);
377 GET_TIME(t2); 406 t2 = get_time();
378 GET_TIME(t3); 407 t3 = get_time();
379 local_irq_restore(flags); 408 local_irq_restore(flags);
380 409
381 port->speed = DELTA(t1, t2) - DELTA(t2, t3); 410 port->speed = delta(t1, t2) - delta(t2, t3);
411 }
382 412
383 tx = ~0; 413 tx = ~0;
384 414
385 for (i = 0; i < 50; i++) { 415 for (i = 0; i < 50; i++) {
386 local_irq_save(flags); 416 local_irq_save(flags);
387 GET_TIME(t1); 417 t1 = get_time();
388 for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); } 418 for (t = 0; t < 50; t++) {
389 GET_TIME(t3); 419 gameport_read(gameport);
420 t2 = get_time();
421 }
422 t3 = get_time();
390 local_irq_restore(flags); 423 local_irq_restore(flags);
391 udelay(i); 424 udelay(i);
392 t = DELTA(t1, t2) - DELTA(t2, t3); 425 t = delta(t1, t2) - delta(t2, t3);
393 if (t < tx) tx = t; 426 if (t < tx) tx = t;
394 } 427 }
395 428