From owner-svn-src-all@FreeBSD.ORG Sat Oct 26 17:25:00 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 5F180B70; Sat, 26 Oct 2013 17:25:00 +0000 (UTC) (envelope-from zbb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 3273128E0; Sat, 26 Oct 2013 17:25:00 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r9QHP0KF058745; Sat, 26 Oct 2013 17:25:00 GMT (envelope-from zbb@svn.freebsd.org) Received: (from zbb@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r9QHOxfn058729; Sat, 26 Oct 2013 17:24:59 GMT (envelope-from zbb@svn.freebsd.org) Message-Id: <201310261724.r9QHOxfn058729@svn.freebsd.org> From: Zbigniew Bodek Date: Sat, 26 Oct 2013 17:24:59 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r257170 - in head/sys/dev: ic uart 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.14 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: Sat, 26 Oct 2013 17:25:00 -0000 Author: zbb Date: Sat Oct 26 17:24:59 2013 New Revision: 257170 URL: http://svnweb.freebsd.org/changeset/base/257170 Log: Wait for DesignWare UART transfers completion before accessing line control When using DW UART with BUSY detection it is necessary to wait until all serial transfers are finished before manipulating the line control. LCR will not be affected when UART is busy. In addition, if Divisor Latch Access Bit is being set in order to modify UART divisors: 1. We will get BUSY interrupt if interrupts are enabled. 2. Because LCR will not be affected the THR and (even worse) IER contents will be corrupted. This will lead to console hang. Approved by: cognet (mentor) Modified: head/sys/dev/ic/ns16550.h head/sys/dev/uart/uart_dev_ns8250.c Modified: head/sys/dev/ic/ns16550.h ============================================================================== --- head/sys/dev/ic/ns16550.h Sat Oct 26 16:49:41 2013 (r257169) +++ head/sys/dev/ic/ns16550.h Sat Oct 26 17:24:59 2013 (r257170) @@ -185,6 +185,7 @@ #define DW_REG_USR 31 /* DesignWare derived Uart Status Reg */ #define com_usr 39 /* Octeon 16750/16550 Uart Status Reg */ #define REG_USR com_usr +#define USR_BUSY 1 /* Uart Busy. Serial transfer in progress */ #define USR_TXFIFO_NOTFULL 2 /* Uart TX FIFO Not full */ /* 16950 register #1. Access enabled by ACR[7]. Also requires !LCR[7]. */ Modified: head/sys/dev/uart/uart_dev_ns8250.c ============================================================================== --- head/sys/dev/uart/uart_dev_ns8250.c Sat Oct 26 16:49:41 2013 (r257169) +++ head/sys/dev/uart/uart_dev_ns8250.c Sat Oct 26 17:24:59 2013 (r257170) @@ -647,11 +647,35 @@ int ns8250_bus_param(struct uart_softc *sc, int baudrate, int databits, int stopbits, int parity) { + struct ns8250_softc *ns8250; struct uart_bas *bas; - int error; + int error, limit; + ns8250 = (struct ns8250_softc*)sc; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); + /* + * When using DW UART with BUSY detection it is necessary to wait + * until all serial transfers are finished before manipulating the + * line control. LCR will not be affected when UART is busy. + */ + if (ns8250->busy_detect != 0) { + /* + * Pick an arbitrary high limit to avoid getting stuck in + * an infinite loop in case when the hardware is broken. + */ + limit = 10 * 1024; + while (((uart_getreg(bas, DW_REG_USR) & USR_BUSY) != 0) && + --limit) + DELAY(4); + + if (limit <= 0) { + /* UART appears to be stuck */ + uart_unlock(sc->sc_hwmtx); + return (EIO); + } + } + error = ns8250_param(bas, baudrate, databits, stopbits, parity); uart_unlock(sc->sc_hwmtx); return (error);