Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Takashi Iwai and committed by
Dmitry Torokhov
76460a7b a3b3ca75

+92 -20
+40 -1
drivers/input/gameport/gameport.c
··· 23 23 #include <linux/workqueue.h> 24 24 #include <linux/sched.h> /* HZ */ 25 25 #include <linux/mutex.h> 26 + #include <linux/timekeeping.h> 26 27 27 28 /*#include <asm/io.h>*/ 28 29 29 30 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 30 31 MODULE_DESCRIPTION("Generic gameport layer"); 31 32 MODULE_LICENSE("GPL"); 33 + 34 + static bool use_ktime = true; 35 + module_param(use_ktime, bool, 0400); 36 + MODULE_PARM_DESC(use_ktime, "Use ktime for measuring I/O speed"); 32 37 33 38 /* 34 39 * gameport_mutex protects entire gameport subsystem and is taken ··· 80 75 */ 81 76 82 77 static int gameport_measure_speed(struct gameport *gameport) 78 + { 79 + unsigned int i, t, tx; 80 + u64 t1, t2, t3; 81 + unsigned long flags; 82 + 83 + if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW)) 84 + return 0; 85 + 86 + tx = ~0; 87 + 88 + for (i = 0; i < 50; i++) { 89 + local_irq_save(flags); 90 + t1 = ktime_get_ns(); 91 + for (t = 0; t < 50; t++) 92 + gameport_read(gameport); 93 + t2 = ktime_get_ns(); 94 + t3 = ktime_get_ns(); 95 + local_irq_restore(flags); 96 + udelay(i * 10); 97 + t = (t2 - t1) - (t3 - t2); 98 + if (t < tx) 99 + tx = t; 100 + } 101 + 102 + gameport_close(gameport); 103 + t = 1000000 * 50; 104 + if (tx) 105 + t /= tx; 106 + return t; 107 + } 108 + 109 + static int old_gameport_measure_speed(struct gameport *gameport) 83 110 { 84 111 #if defined(__i386__) 85 112 ··· 558 521 if (gameport->parent) 559 522 gameport->parent->child = gameport; 560 523 561 - gameport->speed = gameport_measure_speed(gameport); 524 + gameport->speed = use_ktime ? 525 + gameport_measure_speed(gameport) : 526 + old_gameport_measure_speed(gameport); 562 527 563 528 list_add_tail(&gameport->node, &gameport_list); 564 529
+52 -19
drivers/input/joystick/analog.c
··· 36 36 #include <linux/gameport.h> 37 37 #include <linux/jiffies.h> 38 38 #include <linux/timex.h> 39 + #include <linux/timekeeping.h> 39 40 40 41 #define DRIVER_DESC "Analog joystick and gamepad driver" 41 42 42 43 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 43 44 MODULE_DESCRIPTION(DRIVER_DESC); 44 45 MODULE_LICENSE("GPL"); 46 + 47 + static bool use_ktime = true; 48 + module_param(use_ktime, bool, 0400); 49 + MODULE_PARM_DESC(use_ktime, "Use ktime for measuring I/O speed"); 45 50 46 51 /* 47 52 * Option parsing. ··· 176 171 #warning Precise timer not defined for this architecture. 177 172 #endif 178 173 174 + static inline u64 get_time(void) 175 + { 176 + if (use_ktime) { 177 + return ktime_get_ns(); 178 + } else { 179 + unsigned int x; 180 + GET_TIME(x); 181 + return x; 182 + } 183 + } 184 + 185 + static inline unsigned int delta(u64 x, u64 y) 186 + { 187 + if (use_ktime) 188 + return y - x; 189 + else 190 + return DELTA((unsigned int)x, (unsigned int)y); 191 + } 192 + 179 193 /* 180 194 * analog_decode() decodes analog joystick data and reports input events. 181 195 */ ··· 250 226 static int analog_cooked_read(struct analog_port *port) 251 227 { 252 228 struct gameport *gameport = port->gameport; 253 - unsigned int time[4], start, loop, now, loopout, timeout; 229 + u64 time[4], start, loop, now; 230 + unsigned int loopout, timeout; 254 231 unsigned char data[4], this, last; 255 232 unsigned long flags; 256 233 int i, j; ··· 261 236 262 237 local_irq_save(flags); 263 238 gameport_trigger(gameport); 264 - GET_TIME(now); 239 + now = get_time(); 265 240 local_irq_restore(flags); 266 241 267 242 start = now; ··· 274 249 275 250 local_irq_disable(); 276 251 this = gameport_read(gameport) & port->mask; 277 - GET_TIME(now); 252 + now = get_time(); 278 253 local_irq_restore(flags); 279 254 280 - if ((last ^ this) && (DELTA(loop, now) < loopout)) { 255 + if ((last ^ this) && (delta(loop, now) < loopout)) { 281 256 data[i] = last ^ this; 282 257 time[i] = now; 283 258 i++; 284 259 } 285 260 286 - } while (this && (i < 4) && (DELTA(start, now) < timeout)); 261 + } while (this && (i < 4) && (delta(start, now) < timeout)); 287 262 288 263 this <<= 4; 289 264 ··· 291 266 this |= data[i]; 292 267 for (j = 0; j < 4; j++) 293 268 if (data[i] & (1 << j)) 294 - port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop; 269 + port->axes[j] = (delta(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop; 295 270 } 296 271 297 272 return -(this != port->mask); ··· 390 365 static void analog_calibrate_timer(struct analog_port *port) 391 366 { 392 367 struct gameport *gameport = port->gameport; 393 - unsigned int i, t, tx, t1, t2, t3; 368 + unsigned int i, t, tx; 369 + u64 t1, t2, t3; 394 370 unsigned long flags; 395 371 396 - local_irq_save(flags); 397 - GET_TIME(t1); 372 + if (use_ktime) { 373 + port->speed = 1000000; 374 + } else { 375 + local_irq_save(flags); 376 + t1 = get_time(); 398 377 #ifdef FAKE_TIME 399 - analog_faketime += 830; 378 + analog_faketime += 830; 400 379 #endif 401 - mdelay(1); 402 - GET_TIME(t2); 403 - GET_TIME(t3); 404 - local_irq_restore(flags); 380 + mdelay(1); 381 + t2 = get_time(); 382 + t3 = get_time(); 383 + local_irq_restore(flags); 405 384 406 - port->speed = DELTA(t1, t2) - DELTA(t2, t3); 385 + port->speed = delta(t1, t2) - delta(t2, t3); 386 + } 407 387 408 388 tx = ~0; 409 389 410 390 for (i = 0; i < 50; i++) { 411 391 local_irq_save(flags); 412 - GET_TIME(t1); 413 - for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); } 414 - GET_TIME(t3); 392 + t1 = get_time(); 393 + for (t = 0; t < 50; t++) { 394 + gameport_read(gameport); 395 + t2 = get_time(); 396 + } 397 + t3 = get_time(); 415 398 local_irq_restore(flags); 416 399 udelay(i); 417 - t = DELTA(t1, t2) - DELTA(t2, t3); 400 + t = delta(t1, t2) - delta(t2, t3); 418 401 if (t < tx) tx = t; 419 402 } 420 403