svn commit: r331692 - head/sys/dev/usb/input

Hans Petter Selasky hselasky at FreeBSD.org
Wed Mar 28 17:39:24 UTC 2018


Author: hselasky
Date: Wed Mar 28 17:39:23 2018
New Revision: 331692
URL: https://svnweb.freebsd.org/changeset/base/331692

Log:
  Fix for regression issue in USB keyboard driver after r304735.
  
  A series of zero delay callouts can happen causing high CPU usage of the
  timer subsystem when trying to repeat keys, because the time of the
  absolute timeout is not moving forward. The condition clears when all
  keys are released.
  
  Reported by:	Johannes Lundberg <johalun0 at gmail.com>
  Discussed with:	bde@
  PR:		226968
  MFC after:	1 week
  Sponsored by:	Mellanox Technologies

Modified:
  head/sys/dev/usb/input/ukbd.c

Modified: head/sys/dev/usb/input/ukbd.c
==============================================================================
--- head/sys/dev/usb/input/ukbd.c	Wed Mar 28 17:19:04 2018	(r331691)
+++ head/sys/dev/usb/input/ukbd.c	Wed Mar 28 17:39:23 2018	(r331692)
@@ -386,10 +386,22 @@ ukbd_any_key_pressed(struct ukbd_softc *sc)
 static void
 ukbd_start_timer(struct ukbd_softc *sc)
 {
-	sbintime_t delay, prec;
+	sbintime_t delay, now, prec;
 
+	now = sbinuptime();
+
+	/* check if initial delay passed and fallback to key repeat delay */
+	if (sc->sc_delay == 0)
+		sc->sc_delay = sc->sc_kbd.kb_delay2;
+
+	/* compute timeout */
 	delay = SBT_1MS * sc->sc_delay;
 	sc->sc_co_basetime += delay;
+
+	/* check if we are running behind */
+	if (sc->sc_co_basetime < now)
+		sc->sc_co_basetime = now;
+
 	/* This is rarely called, so prefer precision to efficiency. */
 	prec = qmin(delay >> 7, SBT_1MS * 10);
 	usb_callout_reset_sbt(&sc->sc_callout, sc->sc_co_basetime, prec,
@@ -510,7 +522,6 @@ ukbd_get_key(struct ukbd_softc *sc, uint8_t wait)
 static void
 ukbd_interrupt(struct ukbd_softc *sc)
 {
-	struct timeval ctv;
 	uint32_t n_mod;
 	uint32_t o_mod;
 	uint32_t now = sc->sc_time_ms;
@@ -580,14 +591,11 @@ rfound:	;
 				break;
 			}
 		}
-		if (j < UKBD_NKEYCODE) {
-			/* Old key repeating. */
-			sc->sc_delay = sc->sc_kbd.kb_delay2;
-		} else {
-			/* New key. */
-			microuptime(&ctv);
-			sc->sc_co_basetime = tvtosbt(ctv);
+		if (j == UKBD_NKEYCODE) {
+			/* New key - set initial delay and [re]start timer */
+			sc->sc_co_basetime = sbinuptime();
 			sc->sc_delay = sc->sc_kbd.kb_delay1;
+			ukbd_start_timer(sc);
 		}
 		ukbd_put_key(sc, key | KEY_PRESS);
 
@@ -837,10 +845,6 @@ ukbd_intr_callback(struct usb_xfer *xfer, usb_error_t 
 		}
 
 		ukbd_interrupt(sc);
-
-		if (ukbd_any_key_pressed(sc) != 0) {
-			ukbd_start_timer(sc);
-		}
 
 	case USB_ST_SETUP:
 tr_setup:


More information about the svn-src-all mailing list