From owner-svn-src-stable-11@freebsd.org Sun Sep 10 23:48:21 2017 Return-Path: Delivered-To: svn-src-stable-11@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 83053E0ACB1; Sun, 10 Sep 2017 23:48:21 +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 5F1446609D; Sun, 10 Sep 2017 23:48:21 +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 v8ANmKBK003866; Sun, 10 Sep 2017 23:48:20 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v8ANmKpZ003864; Sun, 10 Sep 2017 23:48:20 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201709102348.v8ANmKpZ003864@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore Date: Sun, 10 Sep 2017 23:48:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r323404 - stable/11/sys/arm/freescale/imx X-SVN-Group: stable-11 X-SVN-Commit-Author: ian X-SVN-Commit-Paths: stable/11/sys/arm/freescale/imx X-SVN-Commit-Revision: 323404 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-11@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for only the 11-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 10 Sep 2017 23:48:21 -0000 Author: ian Date: Sun Sep 10 23:48:20 2017 New Revision: 323404 URL: https://svnweb.freebsd.org/changeset/base/323404 Log: MFC r315589, r315591, r316659, r316661: Eliminate unnecessary read/modify/write sequences during eventtimer setup. 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. Remove some old interrupt handling workaround code from the pre-INTRNG days. At this point, INTRNG is not going away (the option may go away, but the code is not), so we no longer need code to support workarounds that handled the lack of INTRNG functionality. Update the code that compensates for the lack of a GPC interrupt controller driver for imx6. Some newer dts source puts the GIC node at the root instead of under /soc, so look in both places. Also, sometimes the GIC node doesn't list itself as its own interrupt-parent, allow that too. Modified: stable/11/sys/arm/freescale/imx/imx6_machdep.c stable/11/sys/arm/freescale/imx/imx_gpt.c Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/arm/freescale/imx/imx6_machdep.c ============================================================================== --- stable/11/sys/arm/freescale/imx/imx6_machdep.c Sun Sep 10 23:41:23 2017 (r323403) +++ stable/11/sys/arm/freescale/imx/imx6_machdep.c Sun Sep 10 23:48:20 2017 (r323404) @@ -52,45 +52,7 @@ __FBSDID("$FreeBSD$"); #include "platform_if.h" -static uint32_t gpio1_node; - -#ifndef INTRNG /* - * Work around the linux workaround for imx6 erratum 006687, in which some - * ethernet interrupts don't go to the GPC and thus won't wake the system from - * Wait mode. We don't use Wait mode (which halts the GIC, leaving only GPC - * interrupts able to wake the system), so we don't experience the bug at all. - * The linux workaround is to reconfigure GPIO1_6 as the ENET interrupt by - * writing magic values to an undocumented IOMUX register, then letting the gpio - * interrupt driver notify the ethernet driver. We'll be able to do all that - * (even though we don't need to) once the INTRNG project is committed and the - * imx_gpio driver becomes an interrupt driver. Until then, this crazy little - * workaround watches for requests to map an interrupt 6 with the interrupt - * controller node referring to gpio1, and it substitutes the proper ffec - * interrupt number. - */ -static int -imx6_decode_fdt(uint32_t iparent, uint32_t *intr, int *interrupt, - int *trig, int *pol) -{ - - if (fdt32_to_cpu(intr[0]) == 6 && - OF_node_from_xref(iparent) == gpio1_node) { - *interrupt = 150; - *trig = INTR_TRIGGER_CONFORM; - *pol = INTR_POLARITY_CONFORM; - return (0); - } - return (gic_decode_fdt(iparent, intr, interrupt, trig, pol)); -} - -fdt_pic_decode_t fdt_pic_table[] = { - &imx6_decode_fdt, - NULL -}; -#endif - -/* * Fix FDT data related to interrupts. * * Driven by the needs of linux and its drivers (as always), the published FDT @@ -109,7 +71,7 @@ fdt_pic_decode_t fdt_pic_table[] = { * We validate that we have data that looks like we expect before changing it: * - SOC node exists and has GPC as its interrupt parent. * - GPC node exists and has GIC as its interrupt parent. - * - GIC node exists and is its own interrupt parent. + * - GIC node exists and is its own interrupt parent or has no parent. * * This applies to all models of imx6. Luckily all of them have the devices * involved at the same addresses on the same busses, so we don't need any @@ -133,14 +95,20 @@ fix_fdt_interrupt_data(void) if (result <= 0) return; + /* GIC node may be child of soc node, or appear directly at root. */ gicnode = OF_finddevice("/soc/interrupt-controller@00a01000"); + if (gicnode == -1) { + gicnode = OF_finddevice("/interrupt-controller@00a01000"); if (gicnode == -1) return; + } + gicxref = OF_xref_from_node(gicnode); + + /* If gic node has no parent, pretend it is its own parent. */ result = OF_getencprop(gicnode, "interrupt-parent", &gicipar, sizeof(gicipar)); if (result <= 0) - return; - gicxref = OF_xref_from_node(gicnode); + gicipar = gicxref; gpcnode = OF_finddevice("/soc/aips-bus@02000000/gpc@020dc000"); if (gpcnode == -1) @@ -184,10 +152,6 @@ imx6_late_init(platform_t plat) const uint32_t IMX6_WDOG_SR_PHYS = 0x020bc004; imx_wdog_init_last_reset(IMX6_WDOG_SR_PHYS); - - /* Cache the gpio1 node handle for imx6_decode_fdt() workaround code. */ - gpio1_node = OF_node_from_xref( - OF_finddevice("/soc/aips-bus@02000000/gpio@0209c000")); } /* Modified: stable/11/sys/arm/freescale/imx/imx_gpt.c ============================================================================== --- stable/11/sys/arm/freescale/imx/imx_gpt.c Sun Sep 10 23:41:23 2017 (r323403) +++ stable/11/sys/arm/freescale/imx/imx_gpt.c Sun Sep 10 23:48:20 2017 (r323404) @@ -84,6 +84,7 @@ struct imx_gpt_softc { uint32_t sc_period; uint32_t sc_clksrc; uint32_t clkfreq; + uint32_t ir_reg; struct eventtimer et; }; @@ -102,10 +103,6 @@ static const int imx_gpt_delay_count = 78; /* 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 +140,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 +246,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; @@ -285,16 +294,20 @@ imx_gpt_timer_start(struct eventtimer *et, sbintime_t /* Set expected value */ WRITE4(sc, IMX_GPT_OCR2, READ4(sc, IMX_GPT_CNT) + sc->sc_period); /* Enable compare register 2 Interrupt */ - SET4(sc, IMX_GPT_IR, GPT_IR_OF2); + sc->ir_reg |= GPT_IR_OF2; + WRITE4(sc, IMX_GPT_IR, sc->ir_reg); return (0); } else if (first != 0) { + /* Enable compare register 3 interrupt if not already on. */ + if ((sc->ir_reg & GPT_IR_OF3) == 0) { + sc->ir_reg |= GPT_IR_OF3; + WRITE4(sc, IMX_GPT_IR, sc->ir_reg); + } ticks = ((uint32_t)et->et_frequency * first) >> 32; /* Do not disturb, otherwise event will be lost */ spinlock_enter(); /* Set expected value */ WRITE4(sc, IMX_GPT_OCR3, READ4(sc, IMX_GPT_CNT) + ticks); - /* Enable compare register 1 Interrupt */ - SET4(sc, IMX_GPT_IR, GPT_IR_OF3); /* Now everybody can relax */ spinlock_exit(); return (0); @@ -310,9 +323,10 @@ imx_gpt_timer_stop(struct eventtimer *et) sc = (struct imx_gpt_softc *)et->et_priv; - /* Disable OF2 Interrupt */ - CLEAR4(sc, IMX_GPT_IR, GPT_IR_OF2); - WRITE4(sc, IMX_GPT_SR, GPT_IR_OF2); + /* Disable interrupts and clear any pending status. */ + sc->ir_reg &= ~(GPT_IR_OF2 | GPT_IR_OF3); + WRITE4(sc, IMX_GPT_IR, sc->ir_reg); + WRITE4(sc, IMX_GPT_SR, GPT_IR_OF2 | GPT_IR_OF3); sc->sc_period = 0; return (0);