From patchwork Wed Oct 18 14:14:46 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Martin X-Patchwork-Id: 10014805 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4A60760215 for ; Wed, 18 Oct 2017 14:22:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3CE4028DE1 for ; Wed, 18 Oct 2017 14:22:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2FE4228DE5; Wed, 18 Oct 2017 14:22:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 91AA528DE1 for ; Wed, 18 Oct 2017 14:22:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=B4OYpa/A0JWLXr7VS94agJ3gfI2+SptHhRizzzQwmHM=; b=jXDmJZ3VfQYPhGlqv44rk3/30G tmeP/0eN36+Hk+ZjMtakOZ3tGcL3TFcDGL6vnVSJA1oZ3fhH1G9kkg8dDDFaPTqjeRVzoThlzoE5q KfXk/F74/zq1alMkXfVjjxeX0//5XIhGfu759Ro/FCFLaLcxJUhIcvAW+laYIuQ14P9WXKB9ZmO4G WH2pJcO9kHJcx3EFblc9elT/xLsymRub0qZK5BAeMaDBDhCZXVvBOMVfE3McPGTVfyEBWXFQIMbOg vH7hkJhKDQ1ZVIP0Mh/jNFEcdguwuMKIQm3BUBBIr0UuFPVXOYrmwNebtpaYPMcR1/IxKwb6rjUnc gZjyCtXA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1e4pFJ-0004Md-IC; Wed, 18 Oct 2017 14:22:57 +0000 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70] helo=foss.arm.com) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1e4p7r-0005yJ-6w for linux-arm-kernel@lists.infradead.org; Wed, 18 Oct 2017 14:15:21 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3BCF415AD; Wed, 18 Oct 2017 07:14:56 -0700 (PDT) Received: from e103592.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.72.51.249]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id D9ECE3F483; Wed, 18 Oct 2017 07:14:54 -0700 (PDT) From: Dave Martin To: linux-arm-kernel@lists.infradead.org Subject: [RFC PATCH 1/3] tty: amba-pl011: earlycon: Switch to relaxed I/O Date: Wed, 18 Oct 2017 15:14:46 +0100 Message-Id: <1508336088-3948-2-git-send-email-Dave.Martin@arm.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1508336088-3948-1-git-send-email-Dave.Martin@arm.com> References: <1508336088-3948-1-git-send-email-Dave.Martin@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20171018_071515_336815_389BA219 X-CRM114-Status: GOOD ( 14.64 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Andre Przywara , Stephen Boyd , Russell King , Andy Gross , linux-serial@vger.kernel.org, Greg Kroah-Hartman , Bhupinder Thakur MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The current pl011 earlycon implementation uses the regular I/O accessors, but this is unnecessary because the architecture enforces ordering of accesses to the same device anyway. Using relaxed I/O brings the added bonus that the generic pl011 helpers can be used instead of having to open-code: this allows some duplicate logic to be unified. This patch does some refactoring so that pl011_{read,write, tx_empty}() are split into a frontend that does the same thing as before, and a backend __* that can be used with a uart_port that has no corresponding uart_amba_port structure yet (i.e., the earlycon scenario). __pl011_tx_empty() can now be used in place of an open-coded poll that differs between the generic and qdf2400_e44 earlycon implementations, because __pl011_tx_empty() handles the necessary quirkage transparently. Moving to relaxed I/O loses wmb() semantics at the start of an earlycon write, and this may be important for some debugging scenarios, so an explicit wmb() is inserted at the start of each earlycon write implementation. Because qdf2400_e44 only supports 32-bit I/O, this patch also explicitly sets port->iotype == UPIO_MEM32 so that __pl011_{write, read}() use the correct I/O size. Signed-off-by: Dave Martin --- drivers/tty/serial/amba-pl011.c | 69 ++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 111e6a9..fd9e08c 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -300,26 +300,38 @@ static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap, return uap->reg_offset[reg]; } -static unsigned int pl011_read(const struct uart_amba_port *uap, - unsigned int reg) +static unsigned int __pl011_read(const struct uart_port *port, + const u16 *reg_offset, unsigned int reg) { - void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg); + void __iomem *addr = port->membase + reg_offset[reg]; - return (uap->port.iotype == UPIO_MEM32) ? + return (port->iotype == UPIO_MEM32) ? readl_relaxed(addr) : readw_relaxed(addr); } -static void pl011_write(unsigned int val, const struct uart_amba_port *uap, +static unsigned int pl011_read(const struct uart_amba_port *uap, unsigned int reg) { - void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg); + return __pl011_read(&uap->port, uap->reg_offset, reg); +} - if (uap->port.iotype == UPIO_MEM32) +static void __pl011_write(unsigned int val, const struct uart_port *port, + const u16 *reg_offset, unsigned int reg) +{ + void __iomem *addr = port->membase + reg_offset[reg]; + + if (port->iotype == UPIO_MEM32) writel_relaxed(val, addr); else writew_relaxed(val, addr); } +static void pl011_write(unsigned int val, const struct uart_amba_port *uap, + unsigned int reg) +{ + __pl011_write(val, &uap->port, uap->reg_offset, reg); +} + /* * Reads up to 256 characters from the FIFO or until it's empty and * inserts them into the TTY layer. Returns the number of characters @@ -1537,16 +1549,23 @@ static irqreturn_t pl011_int(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static unsigned int pl011_tx_empty(struct uart_port *port) +static unsigned int __pl011_tx_empty(struct uart_port *port, + const u16 *reg_offset, const struct vendor_data *vendor) { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); + unsigned int status = __pl011_read(port, reg_offset, REG_FR); /* Allow feature register bits to be inverted to work around errata */ - unsigned int status = pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr; + status ^= vendor->inv_fr; + status &= vendor->fr_busy | UART01x_FR_TXFF; + return status ? 0 : TIOCSER_TEMT; +} - return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ? - 0 : TIOCSER_TEMT; +static unsigned int pl011_tx_empty(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + + return __pl011_tx_empty(port, uap->reg_offset, uap->vendor); } static unsigned int pl011_get_mctrl(struct uart_port *port) @@ -2419,10 +2438,13 @@ static struct console amba_console = { static void qdf2400_e44_putc(struct uart_port *port, int c) { - while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) + const struct vendor_data *vendor = &vendor_qdt_qdf2400_e44; + const u16 *reg_offset = vendor->reg_offset; + + while (__pl011_read(port, reg_offset, REG_FR) & UART01x_FR_TXFF) cpu_relax(); - writel(c, port->membase + UART01x_DR); - while (!(readl(port->membase + UART01x_FR) & UART011_FR_TXFE)) + __pl011_write(c, port, reg_offset, REG_DR); + while (!__pl011_tx_empty(port, reg_offset, vendor)) cpu_relax(); } @@ -2430,18 +2452,19 @@ static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned { struct earlycon_device *dev = con->data; + wmb(); uart_console_write(&dev->port, s, n, qdf2400_e44_putc); } static void pl011_putc(struct uart_port *port, int c) { - while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) + const struct vendor_data *vendor = &vendor_arm; + const u16 *reg_offset = vendor->reg_offset; + + while (__pl011_read(port, reg_offset, REG_FR) & UART01x_FR_TXFF) cpu_relax(); - if (port->iotype == UPIO_MEM32) - writel(c, port->membase + UART01x_DR); - else - writeb(c, port->membase + UART01x_DR); - while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY) + __pl011_write(c, port, reg_offset, REG_DR); + while (!__pl011_tx_empty(port, reg_offset, vendor)) cpu_relax(); } @@ -2449,6 +2472,7 @@ static void pl011_early_write(struct console *con, const char *s, unsigned n) { struct earlycon_device *dev = con->data; + wmb(); uart_console_write(&dev->port, s, n, pl011_putc); } @@ -2494,6 +2518,7 @@ qdf2400_e44_early_console_setup(struct earlycon_device *device, if (!device->port.membase) return -ENODEV; + device->port.iotype = UPIO_MEM32; device->con->write = qdf2400_e44_early_write; return 0; }