From owner-svn-src-head@FreeBSD.ORG Thu Apr 29 06:16:00 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A3239106566B; Thu, 29 Apr 2010 06:16:00 +0000 (UTC) (envelope-from sobomax@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 91A028FC0A; Thu, 29 Apr 2010 06:16:00 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o3T6G0dX005034; Thu, 29 Apr 2010 06:16:00 GMT (envelope-from sobomax@svn.freebsd.org) Received: (from sobomax@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o3T6G0Is005029; Thu, 29 Apr 2010 06:16:00 GMT (envelope-from sobomax@svn.freebsd.org) Message-Id: <201004290616.o3T6G0Is005029@svn.freebsd.org> From: Maxim Sobolev Date: Thu, 29 Apr 2010 06:16:00 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r207354 - head/sys/dev/atkbdc X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 29 Apr 2010 06:16:00 -0000 Author: sobomax Date: Thu Apr 29 06:16:00 2010 New Revision: 207354 URL: http://svn.freebsd.org/changeset/base/207354 Log: On certain chipsets AT keyboard controller isn't present and is emulated by BIOS using SMI interrupt. On those chipsets reading from the status port may be thousand times slower than usually. Sometimes this emilation is not working properly resulting in commands timing out and since we assume that inb() operation takes very little time to complete we need to adjust number of retries to keep waiting time within a designed limits (100ms). Measure time it takes to make read_status() call and adjust number of retries accordingly. To keep it simple, use TSC to measure inb() performance and keep it to amd64-only, since TSC may not available on older CPUs. Also enable detection of the AT controller absence on amd64. Reviewed by: jhb MFC after: 1 month Modified: head/sys/dev/atkbdc/atkbdc.c head/sys/dev/atkbdc/atkbdc_ebus.c head/sys/dev/atkbdc/atkbdc_isa.c head/sys/dev/atkbdc/atkbdcreg.h Modified: head/sys/dev/atkbdc/atkbdc.c ============================================================================== --- head/sys/dev/atkbdc/atkbdc.c Thu Apr 29 05:55:38 2010 (r207353) +++ head/sys/dev/atkbdc/atkbdc.c Thu Apr 29 06:16:00 2010 (r207354) @@ -44,6 +44,10 @@ __FBSDID("$FreeBSD$"); #include #include +#if defined(__amd64__) +#include +#endif + #include #ifdef __sparc64__ @@ -153,7 +157,7 @@ atkbdc_configure(void) bus_space_tag_t tag; bus_space_handle_t h0; bus_space_handle_t h1; -#if defined(__i386__) +#if defined(__i386__) || defined(__amd64__) volatile int i; register_t flags; #endif @@ -222,7 +226,7 @@ atkbdc_configure(void) #endif #endif -#if defined(__i386__) +#if defined(__i386__) || defined(__amd64__) /* * Check if we really have AT keyboard controller. Poll status * register until we get "all clear" indication. If no such @@ -248,6 +252,11 @@ static int atkbdc_setup(atkbdc_softc_t *sc, bus_space_tag_t tag, bus_space_handle_t h0, bus_space_handle_t h1) { +#if defined(__amd64__) + u_int64_t tscval[3], read_delay; + register_t flags; +#endif + if (sc->ioh0 == 0) { /* XXX */ sc->command_byte = -1; sc->command_mask = 0; @@ -264,6 +273,33 @@ atkbdc_setup(atkbdc_softc_t *sc, bus_spa sc->iot = tag; sc->ioh0 = h0; sc->ioh1 = h1; + +#if defined(__amd64__) + /* + * On certain chipsets AT keyboard controller isn't present and is + * emulated by BIOS using SMI interrupt. On those chipsets reading + * from the status port may be thousand times slower than usually. + * Sometimes this emilation is not working properly resulting in + * commands timing our and since we assume that inb() operation + * takes very little time to complete we need to adjust number of + * retries to keep waiting time within a designed limits (100ms). + * Measure time it takes to make read_status() call and adjust + * number of retries accordingly. + */ + flags = intr_disable(); + tscval[0] = rdtsc(); + read_status(sc); + tscval[1] = rdtsc(); + DELAY(1000); + tscval[2] = rdtsc(); + intr_restore(flags); + read_delay = tscval[1] - tscval[0]; + read_delay /= (tscval[2] - tscval[1]) / 1000; + sc->retry = 100000 / ((KBDD_DELAYTIME * 2) + read_delay); +#else + sc->retry = 5000; +#endif + return 0; } @@ -380,10 +416,12 @@ removeq(kqueue *q) static int wait_while_controller_busy(struct atkbdc_softc *kbdc) { - /* CPU will stay inside the loop for 100msec at most */ - int retry = 5000; + int retry; int f; + /* CPU will stay inside the loop for 100msec at most */ + retry = kbdc->retry; + while ((f = read_status(kbdc)) & KBDS_INPUT_BUFFER_FULL) { if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) { DELAY(KBDD_DELAYTIME); @@ -406,10 +444,12 @@ wait_while_controller_busy(struct atkbdc static int wait_for_data(struct atkbdc_softc *kbdc) { - /* CPU will stay inside the loop for 200msec at most */ - int retry = 10000; + int retry; int f; + /* CPU will stay inside the loop for 200msec at most */ + retry = kbdc->retry * 2; + while ((f = read_status(kbdc) & KBDS_ANY_BUFFER_FULL) == 0) { DELAY(KBDC_DELAYTIME); if (--retry < 0) @@ -423,10 +463,12 @@ wait_for_data(struct atkbdc_softc *kbdc) static int wait_for_kbd_data(struct atkbdc_softc *kbdc) { - /* CPU will stay inside the loop for 200msec at most */ - int retry = 10000; + int retry; int f; + /* CPU will stay inside the loop for 200msec at most */ + retry = kbdc->retry * 2; + while ((f = read_status(kbdc) & KBDS_BUFFER_FULL) != KBDS_KBD_BUFFER_FULL) { if (f == KBDS_AUX_BUFFER_FULL) { @@ -448,11 +490,13 @@ wait_for_kbd_data(struct atkbdc_softc *k static int wait_for_kbd_ack(struct atkbdc_softc *kbdc) { - /* CPU will stay inside the loop for 200msec at most */ - int retry = 10000; + int retry; int f; int b; + /* CPU will stay inside the loop for 200msec at most */ + retry = kbdc->retry * 2; + while (retry-- > 0) { if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) { DELAY(KBDD_DELAYTIME); @@ -475,10 +519,12 @@ wait_for_kbd_ack(struct atkbdc_softc *kb static int wait_for_aux_data(struct atkbdc_softc *kbdc) { - /* CPU will stay inside the loop for 200msec at most */ - int retry = 10000; + int retry; int f; + /* CPU will stay inside the loop for 200msec at most */ + retry = kbdc->retry * 2; + while ((f = read_status(kbdc) & KBDS_BUFFER_FULL) != KBDS_AUX_BUFFER_FULL) { if (f == KBDS_KBD_BUFFER_FULL) { @@ -500,11 +546,13 @@ wait_for_aux_data(struct atkbdc_softc *k static int wait_for_aux_ack(struct atkbdc_softc *kbdc) { - /* CPU will stay inside the loop for 200msec at most */ - int retry = 10000; + int retry; int f; int b; + /* CPU will stay inside the loop for 200msec at most */ + retry = kbdc->retry * 2; + while (retry-- > 0) { if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) { DELAY(KBDD_DELAYTIME); Modified: head/sys/dev/atkbdc/atkbdc_ebus.c ============================================================================== --- head/sys/dev/atkbdc/atkbdc_ebus.c Thu Apr 29 05:55:38 2010 (r207353) +++ head/sys/dev/atkbdc/atkbdc_ebus.c Thu Apr 29 06:16:00 2010 (r207354) @@ -202,6 +202,7 @@ atkbdc_ebus_attach(device_t dev) "cannot determine command/data port resource\n"); return (ENXIO); } + sc->retry = 5000; sc->port0 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, start, 1, RF_ACTIVE); if (sc->port0 == NULL) { Modified: head/sys/dev/atkbdc/atkbdc_isa.c ============================================================================== --- head/sys/dev/atkbdc/atkbdc_isa.c Thu Apr 29 05:55:38 2010 (r207353) +++ head/sys/dev/atkbdc/atkbdc_isa.c Thu Apr 29 06:16:00 2010 (r207354) @@ -94,7 +94,7 @@ atkbdc_isa_probe(device_t dev) u_long count; int error; int rid; -#if defined(__i386__) +#if defined(__i386__) || defined(__amd64__) bus_space_tag_t tag; bus_space_handle_t ioh1; volatile int i; @@ -141,7 +141,7 @@ atkbdc_isa_probe(device_t dev) return ENXIO; } -#if defined(__i386__) +#if defined(__i386__) || defined(__amd64__) /* * Check if we really have AT keyboard controller. Poll status * register until we get "all clear" indication. If no such @@ -161,6 +161,8 @@ atkbdc_isa_probe(device_t dev) if (i == 65535) { bus_release_resource(dev, SYS_RES_IOPORT, 0, port0); bus_release_resource(dev, SYS_RES_IOPORT, 1, port1); + if (bootverbose) + device_printf(dev, "AT keyboard controller not found\n"); return ENXIO; } #endif @@ -201,6 +203,7 @@ atkbdc_isa_attach(device_t dev) } rid = 0; + sc->retry = 5000; sc->port0 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); if (sc->port0 == NULL) Modified: head/sys/dev/atkbdc/atkbdcreg.h ============================================================================== --- head/sys/dev/atkbdc/atkbdcreg.h Thu Apr 29 05:55:38 2010 (r207353) +++ head/sys/dev/atkbdc/atkbdcreg.h Thu Apr 29 06:16:00 2010 (r207354) @@ -200,6 +200,7 @@ typedef struct atkbdc_softc { int lock; /* FIXME: XXX not quite a semaphore... */ kqueue kbd; /* keyboard data queue */ kqueue aux; /* auxiliary data queue */ + int retry; } atkbdc_softc_t; enum kbdc_device_ivar {