From owner-svn-src-all@freebsd.org Sun Mar 19 21:53:13 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id B4F58D13DAA; Sun, 19 Mar 2017 21:53:13 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 740BAB8B; Sun, 19 Mar 2017 21:53:13 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v2JLrC8T050452; Sun, 19 Mar 2017 21:53:12 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v2JLrCPr050451; Sun, 19 Mar 2017 21:53:12 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201703192153.v2JLrCPr050451@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore Date: Sun, 19 Mar 2017 21:53:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r315591 - head/sys/arm/freescale/imx X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 19 Mar 2017 21:53:13 -0000 Author: ian Date: Sun Mar 19 21:53:12 2017 New Revision: 315591 URL: https://svnweb.freebsd.org/changeset/base/315591 Log: Replace the hard-coded way-too-small minimum event timer period with a value calculated at runtime based on how long it takes to set up an event in hardware. This fixes the intermittant 1-minute hang at boot on imx5 systems, and also the occasional oversleeping while running. It doesn't affect imx6 systems, which use different hardware for eventtimers. It turns out that it usually takes about 30 timer ticks to set up the timer compare register, and the old hard-coded minimum period was 10 ticks. On the rare occasions when a timeout event that short was set up, we'd miss the event and have to wait about 64 seconds for counter rollover before the compare interrupt would fire. Instead of just hardcoding a new bigger value, the code now measures the time it takes to do the register read/write sequence to set up the compare register, scales it up by 1.5x to be safe, and calculates the minimum event period from the result. In the real world, the minimum period works out to about 750 nanoseconds on imx5 hardware. Modified: head/sys/arm/freescale/imx/imx_gpt.c Modified: head/sys/arm/freescale/imx/imx_gpt.c ============================================================================== --- head/sys/arm/freescale/imx/imx_gpt.c Sun Mar 19 21:49:15 2017 (r315590) +++ head/sys/arm/freescale/imx/imx_gpt.c Sun Mar 19 21:53:12 2017 (r315591) @@ -102,10 +102,6 @@ static const int imx_gpt_delay_count = 7 /* Try to divide down an available fast clock to this frequency. */ #define TARGET_FREQUENCY 1000000000 -/* Don't try to set an event timer period smaller than this. */ -#define MIN_ET_PERIOD 10LLU - - static struct resource_spec imx_gpt_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, @@ -143,7 +139,7 @@ imx_gpt_attach(device_t dev) { struct imx_gpt_softc *sc; int ctlreg, err; - uint32_t basefreq, prescale; + uint32_t basefreq, prescale, setup_ticks, t1, t2; sc = device_get_softc(dev); @@ -249,13 +245,25 @@ imx_gpt_attach(device_t dev) return (ENXIO); } + /* + * Measure how many clock ticks it takes to setup a one-shot event (it's + * longer than you might think, due to wait states in accessing gpt + * registers). Scale up the result by a factor of 1.5 to be safe, + * and use that to set the minimum eventtimer period we can schedule. In + * the real world, the value works out to about 750ns on imx5 hardware. + */ + t1 = READ4(sc, IMX_GPT_CNT); + WRITE4(sc, IMX_GPT_OCR3, 0); + t2 = READ4(sc, IMX_GPT_CNT); + setup_ticks = ((t2 - t1 + 1) * 3) / 2; + /* Register as an eventtimer. */ sc->et.et_name = "iMXGPT"; sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC; sc->et.et_quality = 800; sc->et.et_frequency = sc->clkfreq; - sc->et.et_min_period = (MIN_ET_PERIOD << 32) / sc->et.et_frequency; - sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; + sc->et.et_min_period = ((uint64_t)setup_ticks << 32) / sc->clkfreq; + sc->et.et_max_period = ((uint64_t)0xfffffffe << 32) / sc->clkfreq; sc->et.et_start = imx_gpt_timer_start; sc->et.et_stop = imx_gpt_timer_stop; sc->et.et_priv = sc;