From patchwork Mon Sep 29 18:06:48 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Andrzej Siewior X-Patchwork-Id: 4998591 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id D57479F2BA for ; Mon, 29 Sep 2014 18:27:57 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id EBEAB201BC for ; Mon, 29 Sep 2014 18:27:56 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F244620160 for ; Mon, 29 Sep 2014 18:27:55 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XYfe1-0007rz-Ei; Mon, 29 Sep 2014 18:25:57 +0000 Received: from galois.linutronix.de ([2001:470:1f0b:db:abcd:42:0:1]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XYfdx-0007gu-T6 for linux-arm-kernel@lists.infradead.org; Mon, 29 Sep 2014 18:25:54 +0000 Received: from localhost ([127.0.0.1] helo=bazinga.breakpoint.cc) by Galois.linutronix.de with esmtp (Exim 4.80) (envelope-from ) id 1XYfLh-0001xV-2j; Mon, 29 Sep 2014 20:07:01 +0200 From: Sebastian Andrzej Siewior To: linux-serial@vger.kernel.org Subject: [PATCH 12/13] tty: serial: 8250: omap: add custom irq handling Date: Mon, 29 Sep 2014 20:06:48 +0200 Message-Id: <1412014009-13315-13-git-send-email-bigeasy@linutronix.de> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1412014009-13315-1-git-send-email-bigeasy@linutronix.de> References: <1412014009-13315-1-git-send-email-bigeasy@linutronix.de> X-Linutronix-Spam-Score: -1.0 X-Linutronix-Spam-Level: - X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required, ALL_TRUSTED=-1, SHORTCIRCUIT=-0.0001, URIBL_BLOCKED=0.001 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140929_112554_093800_0348ECB4 X-CRM114-Status: GOOD ( 15.60 ) X-Spam-Score: -0.8 (/) Cc: Heikki Krogerus , Peter Hurley , tony@atomide.com, gregkh@linuxfoundation.org, Sebastian Andrzej Siewior , linux-kernel@vger.kernel.org, balbi@ti.com, linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP We have (or will have) custom DMA callbacks in the omap driver due to the different behaviour in the RX and TX case. To make this work we need a few changes in the IRQ handler to invoke the rx_handler again after the "manual" mode or retry the tx_handler again before falling back to the manual mode. Heikki didn't want to see the extra hacks in the generic / default irq handler and Peter wasn't too happy about an OMAP-only IRQ handler. The way I planned it is to use this extra IRQ routine only in DMA case. If Peter dislike this approach then I hope Heikki doesn't block changes in the default IRQ handler :) Cc: Heikki Krogerus Cc: Peter Hurley Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: Heikki Krogerus --- drivers/tty/serial/8250/8250.h | 2 ++ drivers/tty/serial/8250/8250_core.c | 6 ++-- drivers/tty/serial/8250/8250_omap.c | 55 +++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 4bb831ab5db0..28097a912c10 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -119,6 +119,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value) } struct uart_8250_port *serial8250_get_port(int line); +void serial8250_rpm_get(struct uart_8250_port *p); +void serial8250_rpm_put(struct uart_8250_port *p); #if defined(__alpha__) && !defined(CONFIG_PCI) /* diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 93b0799936fd..6a3b4399bf3c 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -541,20 +541,22 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) } EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); -static void serial8250_rpm_get(struct uart_8250_port *p) +void serial8250_rpm_get(struct uart_8250_port *p) { if (!(p->capabilities & UART_CAP_RPM)) return; pm_runtime_get_sync(p->port.dev); } +EXPORT_SYMBOL_GPL(serial8250_rpm_get); -static void serial8250_rpm_put(struct uart_8250_port *p) +void serial8250_rpm_put(struct uart_8250_port *p) { if (!(p->capabilities & UART_CAP_RPM)) return; pm_runtime_mark_last_busy(p->port.dev); pm_runtime_put_autosuspend(p->port.dev); } +EXPORT_SYMBOL_GPL(serial8250_rpm_put); /* * These two wrappers ensure that enable_runtime_pm_tx() can be called more than diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 1659858e595a..6500547f8fda 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -854,6 +855,60 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) return ret; } +/* + * This is mostly serial8250_handle_irq(). We have a slightly different DMA + * hoook for RX/TX and need different logic for them in the ISR. Therefore we + * use the default routine in the non-DMA case and this one for with DMA. + */ +static int omap_8250_dma_handle_irq(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char status; + unsigned long flags; + u8 iir; + int dma_err = 0; + + serial8250_rpm_get(up); + + iir = serial_port_in(port, UART_IIR); + if (iir & UART_IIR_NO_INT) { + serial8250_rpm_put(up); + return 0; + } + + spin_lock_irqsave(&port->lock, flags); + + status = serial_port_in(port, UART_LSR); + + if (status & (UART_LSR_DR | UART_LSR_BI)) { + + dma_err = omap_8250_rx_dma(up, iir); + if (dma_err) { + status = serial8250_rx_chars(up, status); + omap_8250_rx_dma(up, 0); + } + } + serial8250_modem_status(up); + if (status & UART_LSR_THRE && up->dma->tx_err) { + if (uart_tx_stopped(&up->port) || + uart_circ_empty(&up->port.state->xmit)) { + up->dma->tx_err = 0; + serial8250_tx_chars(up); + } else { + /* + * try again due to an earlier failer which + * might have been resolved by now. + */ + dma_err = omap_8250_tx_dma(up); + if (dma_err) + serial8250_tx_chars(up); + } + } + + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); + return 1; +} #endif static int omap8250_probe(struct platform_device *pdev)